ist `Warnung C4127` (bedingter Ausdruck ist konstant) jemals hilfreich?

Lesezeit: 5 Minuten

[*]
Mohit Jain

Bei der Beantwortung dieses Beitrags schlug ich vor, zu verwenden do {...} while(0) für mehrzeilige Makros.

Auf MSVC fand ich diesen Code:

warning C4127: conditional expression is constant

Um Code warnungsfrei zu machen, muss ich eine dieser hässlichen Alternativen wählen:

Option 1

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4127)
#endif
code_using_macro_that_generates_C4217;
#ifdef _MSC_VER
#pragma warning(pop)
#endif

Option 2

Definiere meine Makros als:

#define MULTI_LINE_MACRO do { ... } while(0,0)

oder

#define MULTI_LINE_MACRO do { ... } while((void)0,0)

Von einigen Programmierern auch als “Eule” bezeichnet (0,0) sieht aus wie eine Eule.

Möglichkeit 3

Definieren Sie ein neues Makro WHILE_0, das keine Warnung generiert, und verwenden Sie es stattdessen while(0)

Problem

Ich glaube, alle Alternativen sind mehr oder weniger schrecklich. Warum generiert MSVC diese Warnung für scheinbar korrekten Code und motiviert mich, meinem Code etwas Hässlichkeit hinzuzufügen, um die Codewarnung frei zu halten?

Ich glaube, dass konstante Ausdrücke in Bedingungen absolut gültig und nützlich sind, insbesondere in Konstrukten, die auf der Fähigkeit des Compilers basieren, unseren Code zu optimieren.

Außerdem bekomme ich keine warning C4127 für Code wie diesen:

void foo(unsigned bar)
{
    while (bar >= 0)
        ;
} 

Meine Frage ist: Ist nicht warning C4127: conditional expression is constant völlig nutzlos und motiviert es nicht zu hässlichem Code? Hilft diese Warnung jemals dabei, besseren Code zu schreiben?

  • @ Bathseba: aber for(;;) hat nicht die gleiche Bedeutung wie do{}while(0) !!!!

    – Basile Starynkevitch

    11. März 2015 um 11:34 Uhr

  • Entferne das pragma und #include “no_sillywarnings_please.h”

    – David Ranieri

    11. März 2015 um 11:38 Uhr


  • @GiulioFranco: Es löst nicht was do { ... } while(0) löst. if(foo) for(;;) { ...; break; }; else bar(); ist ein Syntaxfehler.

    – Mafso

    11. März 2015 um 11:46 Uhr

  • @BoykoPerfanov #define ABC(X) {something;} schlägt die Kompilierung fehl, wenn sie aufgerufen wird als: if(cond) ABC(42); else {}

    – Mohit Jain

    11. März 2015 um 14:08 Uhr

  • Nein, ich denke, es ist nie hilfreich. Übrigens sind Eulen süß.

    – Gyapti Jain

    12. März 2015 um 7:11 Uhr

Ich glaube nicht, dass es jemals nützlich ist. Im Gegenteil, es gibt mehr Fehlalarme als nur die do .. while(0) Idiom. Denken Sie an Konstrukte wie

if(sizeof(long) == 8) { /* ... */ }
if(SOME_CONSTANT_MACRO) { /* ... */ }

Ersteres kann nicht ersetzt werden durch #if Direktiven, Letzteres könnte, aber einige Codierungsstilrichtlinien bevorzugen die if Version, da die Syntaxprüfung immer noch für den toten Code durchgeführt wird (der auf anderen Plattformen oder mit einer anderen Konfiguration zur Kompilierzeit nicht tot ist) und einige finden es besser zu lesen.

Warnungen (andere als die vom Standard geforderten, von denen die meisten als Fehler behandelt werden sollten) werden normalerweise für Code ausgegeben, der gültig ist, aber wahrscheinlich etwas anderes als beabsichtigt tut. if(0) oder solche Dinge sehen albern aus, aber sehen nicht so aus, als ob etwas anderes als “Syntaxprüfung dieses ansonsten toten Codes” beabsichtigt war. Es mag den Leser verwirren, aber es ist eindeutig, und ich sehe nicht, wie dies versehentlich passieren könnte.

Aus den bisher gegebenen Beispielen (ich habe MSVC nicht zum Testen selbst) scheint es, als ob die Warnung für konstante Ausdrücke im Sinne der C-Sprache gilt (d.h. nicht etwas, das konstant gefaltet werden kann, sondern syntaktisch ist kein konstanter Ausdruck), wird also nicht ausgegeben für if(array)oder if(function) (was zB gcc -Wall warnt davor, weil es wahrscheinlich ein Funktionsaufruf sein soll).

while(0,0) schlimmer ist meiner Meinung nach, es löst eine Abmahnung mit aus gcc -Wall für eine linke Seite eines Kommaoperators ohne Seiteneffekte eine Warnung, die ich mir gelegentlich als nützlich vorstellen kann (und die normalerweise leicht zu vermeiden ist). Diese Warnung verschwindet mit while((void)0,0).

Ich schlage vor, die Warnung auszuschalten.

Eine Warnung, dass ein bedingter Ausdruck sicherlich konstant ist kann nützlich sein. Es kann in vielen Fällen auf einen logischen Fehler in Ihrem Code hinweisen.

Wenn Sie zum Beispiel so etwas schreiben:

if (x != NULL) { /* ... */ }

wo x ein Array-Objekt ist, ist der Ausdruck gültig, aber der Ausdruck x zerfällt zu einem Zeiger auf das Anfangselement des Arrays, das kann nicht ein Nullzeiger sein. Ich weiß nicht, ob das den gleichen Fehler erzeugt, aber es ist ein Beispiel für die gleiche Art von Sache.

Natürlich nicht stets nützlich. In Ihrem Fall die

do { /* ... */ } while (0)

Idiom ist der beste Weg, um eine Makrodefinition zu schreiben, die in einem Kontext verwendet werden soll, der eine Anweisung erfordert. Verwenden while (0) in einem anderen Zusammenhang dürfte es sich um einen logischen Fehler handeln [*].

Es ist bedauerlich, dass Ihr Compiler es nicht als allgemeines Idiom erkennt. Gute Warnungen zu generieren ist schwierig; der Compiler muss über die Regeln der Sprache hinausgehen und auf die Absicht des Programmierers schließen.

In diesem Fall ist es wahrscheinlich der beste Ansatz, eine Compiler-spezifische Methode zu verwenden, um die Warnung zu unterdrücken (solange sie den Code für andere Compiler nicht beschädigt). Die Verwendung einer Befehlszeilenoption zum Unterdrücken der Warnung in allen Fällen wäre übertrieben. Sie könnten an anderer Stelle in Ihrem Code gültige Warnungen übersehen.

Anscheinend schreiben while (0,0) statt while (0) vermeidet die Warnung. Wenn Sie dies tun, sollten Sie einen Kommentar hinzufügen, der deutlich angibt, dass es sich um eine Problemumgehung für Ihren speziellen Compiler handelt. Es gibt keinen besonderen Grund, vor dem ein Compiler nicht warnen sollte while (0,0) oder irgendein anderer äquivalenter Code.

[*] Es kann sinnvoll sein, a zu schreiben do { /* ... */ } while (0) Anweisung, wenn Sie verwenden möchten break daraus herauszuspringen.

  • Aus den bisher gegebenen Beispielen sieht es so aus, als ob die Warnung nur für konstante Ausdrücke ausgelöst wird (nicht für nicht konstante Konstrukte, die konstant gefaltet werden können), also wird sie nicht ausgegeben für if(x != NULL). Warum wird es sonst nicht ausgelöst? if(0,0)?

    – Mafso

    18. März 2015 um 11:24 Uhr

1098340cookie-checkist `Warnung C4127` (bedingter Ausdruck ist konstant) jemals hilfreich?

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

Privacy policy