Compiler-Warnung generieren, wenn const char* Array-Initialisierungskomma fehlt

Lesezeit: 3 Minuten

Benutzeravatar von Jonny Schubert
Jonny Schubert

Ich verwende in meinem C-Code häufig String-Literal-Tabellen. Diese Tabellen sehen alle mehr oder weniger so aus:

static const char* const stateNames[STATE_AMOUNT] =
{
    "Init state",
    "Run state",
    "Pause state",
    "Error state",
};

Das Problem mit dem obigen Code ist, wenn die Tabelle länger wird und während der Entwicklung geändert wird, vergesse ich von Zeit zu Zeit ein Komma. Der Code lässt sich ohne Probleme mit einem fehlenden Komma kompilieren, aber mein Programm stürzt ab, da die letzte Zeichenfolge auf gesetzt ist NULL. Ich habe die MinGW- und Keil-Compiler zur Überprüfung verwendet.

Gibt es eine Möglichkeit, eine Compiler-Warnung für meine Initialisierung zu generieren, wenn das Komma fehlt?

  • Was passiert, wenn Sie einfach vergessen, dieser Tabelle einen Status hinzuzufügen?

    – Jeroen3

    27. Januar 2020 um 9:00 Uhr

  • @ Jeroen3 true, dies würde den gleichen Fehler verursachen. Die Verwendung eines statischen Assertion-Tests der Listenlänge gegen den STATE_AMOUNT löst dieses Problem ebenfalls.

    – Jonny Schubert

    27. Januar 2020 um 9:48 Uhr

Benutzeravatar von Davide Spataro
David Spataro

Verpackung jeden const char* in einem Paar Klammern sollte das Problem lösen, wie im folgenden Ausschnitt gezeigt:

static const char* const stateNames[5] =
{
    ("Init state"),
    ("Run state"),
    ("Pause state")     //comma missing
    ("Pause state3"),
    ("Error state")
};

Wenn Sie ein Komma vergessen, erhalten Sie einen Kompilierungsfehler ähnlich dem folgenden: error: called object is not a function or function pointer

LIVE-DEMO


Beachten Sie, dass, wenn Sie das Komma vergessen, C tatsächlich die zwei (oder mehr) Zeichenfolgen bis zum nächsten Komma oder dem Ende des Arrays verkettet. Nehmen wir zum Beispiel an, Sie vergessen das Komma, wie im Folgenden gezeigt:

static const char* const stateNames[] =
{
    "Init state",
    "Run state",
    "Pause state" //comma missing
    "Pause state3" //comma missing
    "Error state"
};

int main(void)
{  
    printf("%s\n", stateNames[0]);
    return 0;    
}

Das ist was gcc-9.2 erzeugt (andere Compiler generieren ähnlichen Code):

.LC0:
        .string "Init state"
        .string "Run state"
        .string "Pause statePause state3Error state" ; oooops look what happened
        .quad   .LC0
        .quad   .LC1
        .quad   .LC2
main:
        push    rbp
        mov     rbp, rsp
        mov     eax, OFFSET FLAT:.LC0
        mov     rdi, rax
        call    puts
        mov     eax, 0
        pop     rbp
        ret

Es ist klar, dass die letzten drei Zeichenfolgen verkettet sind und das Array nicht die erwartete Länge hat.

Benutzeravatar von MM
MM

Sie könnten den Compiler das Array zählen lassen und bei unerwartetem Ergebnis eine Fehlermeldung generieren:

enum { STATE_AMOUNT = 4 };

static const char* const stateNames[] =
{
    "Init state",
    "Run state",
    "Pause state"    // <--- missing comma
    "Error state",
};

_Static_assert( sizeof stateNames / sizeof *stateNames == STATE_AMOUNT,
        "oops, missed a comma" );

In diesem Thread finden Sie Ideen zur Umsetzung _Static_assert wenn Ihr Compiler sehr alt ist und ihn nicht unterstützt.

Als Bonus kann dies auch helfen, wenn Sie neue Zustände hinzufügen, aber vergessen, die Zeichenfolgentabelle zu aktualisieren. Aber vielleicht möchten Sie sich auch mit X-Makros befassen.

  • Verdammt … das war genau die Antwort, die ich gerade eingeben wollte!

    – Der Schweißer

    16. Februar 2020 um 4:02 Uhr

Ich habe immer einen Verweis auf ein Array mit expliziter Größe verwendet, um dies zu lösen.

// no explicit size here
static const char* const stateNames[] =
{
    "Init state",
    "Run state",
    "Pause state",
    "Error state",
};
static const char* const (&stateNameVerifier)[STATE_AMOUNT] = stateNames;

http://coliru.stacked-crooked.com/a/593fc2eac80782a6

main.cpp:10:32: error: reference to type 'const char *const [5]' could not bind to an lvalue of type 'const char *const [4]'
static const char* const (&stateNameVerifier)[STATE_AMOUNT] = stateNames;

  • Eine statische Behauptung scheint eine viel elegantere Lösung zu sein. Ich nehme an, Sie haben sich angewöhnt, dies zu tun, bevor statische Behauptungen als Teil der Sprache implementiert wurden? Sehen Sie jetzt immer noch einen Vorteil gegenüber einer statischen Assertion, die die erwartete Größe des Arrays überprüft?

    – Cody Grey

    27. Januar 2020 um 20:10 Uhr


  • @CodyGray: Ja, das war eine vorstatische Behauptung, jetzt wo du es erwähnst

    – Muhende Ente

    27. Januar 2020 um 21:28 Uhr

Dies bringt den Compiler nicht dazu, Ihnen zu helfen, aber ich finde, es wie unten zu schreiben, macht es für Menschen einfacher, kein Komma fallen zu lassen:

static const char* const stateNames[STATE_AMOUNT] =
{
      "Init state"
    , "Run state"
    , "Pause state"
    , "Error state"
};

1410970cookie-checkCompiler-Warnung generieren, wenn const char* Array-Initialisierungskomma fehlt

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy