2016-08-08 15 views
1

Wenn cppcheck über diesen Code ausgeführt wird, [1] es beschwert sich über ein Fehler:auf eine nicht-triviale Bool Szenario in C Stolper ++

void bool_express(bool aPre, bool aX, bool aPost) 
{ 
    bool x; 
    const bool pre = aPre; 
    if (pre) { 
     x = aX; 
    } 
    const bool post = aPost; 

    // error checking passage of the original code: 
    if (!pre || !x || !post) { 
     if (!pre) { 
      trace("pre failed"); 
     } else if (!x) {  // <-- HERE Cppcheck complains 
      trace("x failed"); 
     } else { 
      trace("post failed"); 
     } 
    } else { 
     // success passage of the original code: 
     trace("ok"); 
    } 
} 

Dies ist die Botschaft, das macht mich nervös:

Id: uninitvar 
Summary: Uninitialized variable: x 
Message: Uninitialized variable: x 

Ich denke, es ist ein falsches positives, aber ich gebe zu, dass dies nicht offensichtlich sein kann. Trotzdem möchte ich diesen Code nicht anfassen, weil er alt und viel schwerer ist als diese extrahierte Version.

Haben Sie schon einmal Situationen wie diese erlebt? Wie man damit umgeht?


[1] Dieser Code auf seine Knochen reduziert wird, stellt der ursprüngliche Code Voraussetzung (pre), tut etwas (x), dann eine Nachbedingung zwingt (post), nach, dass einige Bedingungen Fehler sind überprüft. Ich habe die Laufzeit-Ergebnisse der aufgerufenen Funktionen transformiert und dann in pre, x und post in die 3 Argumente meines Testfalls geschrieben.

+0

sagen wir Klockworks für statische Code-Analyse verwenden, und es zeigt den Fluss, in der 'x 'wird nicht initialisiert verwendet, wenn Cppcheck diese Option hat und vielleicht etwas anderes fehlt, obwohl es für mich wie ein falsches Positiv aussieht – ZivS

+2

Hast du sichergestellt, dass die reduzierte Version immer noch die CppCheck Warnung erzeugt? – nwp

+2

Wie wäre es, wenn Sie 'x' einfach auf false initialisieren? Ich kann mir kein realistisches Szenario vorstellen, in dem das explodieren würde. – nwp

Antwort

0

Wenn Ihre pre Bedingung ist false als x wird nicht initialisiert werden. In der Zeile if (!x) warnt CppCheck vor der Verwendung eines unbestimmten Wertes. Um es zu beheben initialisieren x Variable.

+0

Wenn 'pre'' 'false' 'ist, dann wird'! X' nicht geprüft, da es sich um einen Kurzschluss oder eine faule Auswertung handelt, kann sich nicht erinnern, wie es heißt. – nwp

+0

Ich denke, es ist nicht einmal kurzgeschlossen, aber einfach unmöglich, dass "x" nicht initialisiert ist, wenn "pre" wahr ist. Nun, die Initialisierung von 'x' wird nicht schaden, ja. – Wolf

+0

@nwp @Wolf Sie haben Recht, '! X' checkt nicht'! Pre || ein ! x || ! post' in diesem Fall. Aber anscheinend hat CppCheck keine richtige Wertverbreitung, um zu verstehen, dass 'if (! X)' ebenfalls nicht ausgeführt wird. Auch hier ist es besser, vor einem möglichen Problem zu warnen, da es bei äußerer Bedingung '! Pre || ein echtes Problem verursachen kann ! x || ! post' wird geändert. – Nikita

1

Die statische Analyse scheint sich zu beschweren, denn wenn pre falsch ist, dann wird x nie gesetzt.

Ihr Code ist so aufgebaut, dass der Wert von x nie, wenn prezugegriffen wird, ist falsch - ich würde behaupten, dass der statische Analysator ist eine Nutzleistung in diesem Fall nicht zu geben.

Auflisten der verschiedenen Fälle, die wir haben (so können wir ziemlich sicher sein, dass es cppcheck und uns!):

  1. Die erste Erklärung, in der x zugegriffen wird, in der Linie ist if (!pre || !x || !post) - aufgrund short-circuiting evaluation : if(A || B || C) wertet B oder C nicht aus, wenn A wahr ist; daher versuchen wir nie ein uninitialised x zu lesen (seit x nur uninitialised wenn pre falsch ist, in diesem Fall werden wir gestoppt, um den Ausdruck ausgewertet!)

  2. Die zweite Anwendung ist in

    if (!pre) { trace("pre failed"); } else if (!x) { // <-- HERE Cppcheck complains

    Wieder , können wir nur die betreffende Linie treffen, wenn pre wahr war (in diesem Fall wird x richtig initialisiert).

Daraus können wir schließen, dass entweder:

  1. Der eigentliche Code versucht fälschlicherweise x in einem gewissen Zustand zu lesen selbst ist pre falsch ist, und Sie haben es verpasst, wenn das Beispiel Gebäude (manchmal kann der logische Ablauf eines Programms ein wenig stumpf sein)

  2. Der statische Analysator ist faul und erspäht die Zeile else if(!x) und kann nicht feststellen, ob diese Zeile mit einem nicht initialisierten Wert erreichbar ist.

Aus dem Code, den Sie zur Verfügung gestellt haben, sollten Sie sich keine Sorgen: die statische Analyse-Tool ist technisch korrekt, dass x uninitialised werden kann, aber in diesen Fällen sollte es nicht verwendet wird (und daher wahrscheinlich nicht warne dich).

Ich würde empfehlen, x einen Standardwert zuzuweisen, wenn Sie nicht sicher sind, oder wenn die tatsächliche Logik äußerst stumpf ist.

+0

Verwenden Sie besser die C/C++ - Version von ** oder ** ('||') anstelle von ** binary oder ** ('|'). – Wolf

+0

@Wolf Whoops! Korrigiert! – KidneyChris

+0

Bitte ** beziehen Sie sich hier nicht auf einen Kurzschluss, weil es einfach falsch ist **. Kurzschlüsse werden für boolesche * Ausdrücke * verwendet und im gezeigten Fall ist der einzige Ausdruck, der (wahrscheinlich) kurzgeschlossen ist, "(! Pre ||! X ||! Post") und wird übergeben 7 von 8 Fällen, besonders in allen Fällen, in denen "! Pre" ist, ist der Punkt, dass "x" nur ausgewertet wird, wenn "!! pre", mit anderen Worten, wenn "pre" "wahr" ist. – Wolf

1

Es ist ein falsch positives in Cppcheck. Ich löste es durch eine Inline-Unterdrückung und fügte hinzu: [1]

if (!pre) { 
     trace("pre failed"); 
    // cppcheck-suppress uninitvar 
    } else if (!x) { 
     trace("x failed"); 
    } else { 
     trace("post failed"); 
    } 

und ich brachte es auch auf die Aufmerksamkeit der cppcheck Entwickler:

#7663 (False positive: uninitialised variable in unreachable code)


[ 1] Ich habe mich entschieden, die Variable nicht zu initialisieren. Dies ist nicht aus Leistungsgründen, sondern um die Fehler in einer zukünftigen Version behoben werden, informiert zu werden, wenn cppcheck

Id: unmatchedSuppression 
Summary: Unmatched suppression: uninitvar 
Message: Unmatched suppression: uninitvar