2016-05-17 10 views
1

sagen, dass wir die folgende for-Schleife haben:Wie elegant vermeiden "Condition is always true" Warnung für diese besondere Art von For-Schleife?

#define UPPER 0U 
int i; 
for(i = 0; i < UPPER; i++) { 
    /* foo */ 
} 

Dies wird produzieren eine W549: condition is always true Warnung, offensichtlich, weil wir for(i = 0; i < 0; i++) nach Makroerweiterung erhalten. In dem tatsächlichen Code ist UPPER ein Vorkompilierungszeitparameter (d. H. Er wird durch einige Erstellungsskripte abhängig von der Zielplattform usw. gesetzt), die irgendeinen Wert von 0 bis 255 annehmen können, und somit ist die Schleife nicht nur ein toter Code.

Wie kann ich diese Warnung elegant vermeiden, wenn UPPER == 0?

Offensichtlich kann man wickeln Sie die for-Schleife in einer if-Anweisung:

#define UPPER 0U 
if(UPPER != 0U) { 
    int i; 
    for(i = 0; i < UPPER; i++) { 
     /* foo */ 
    } 
} 

Aber das ist nicht das, was ich elegant nennen würde.

+0

1) haben Sie versucht, Ihre Sniplet zu kompilieren? '# define' sollte kein' = 'und'; 'haben. 2) In Ihrem Beispiel ist die Bedingung beim ersten Versuch falsch, so dass die Schleife vollständig übersprungen wird. – Serge

+0

@Serge: Nein, ich tippte es einfach und dachte: "Was könnte * möglicherweise * schief gehen mit diesem kleinen Ausschnitt". Für den zweiten Punkt: ja, wenn "UPPER" als 0 definiert ist. Aber wie ich in der Frage zu erklären versuchte, ist dies ein Pre-Compile-Parameter, dh er kann andere Werte als 0 haben und somit ist die for-Schleife kein toter Code. – mort

+0

@AjeetShah: Um sicherzustellen, dass ich richtig verstehe: Sie schlagen vor, eine neue Variable einzuführen, sagen wir "volatile int upper = UPPER;" und verwenden Sie diese in der for-Schleife? – mort

Antwort

3

Wenn Sie es im Code nicht wickeln möchten, den Code mit der bedingten Kompilierung wickeln:

#if UPPER > 0 
    int i; 
    for(i = 0; i < UPPER; i++) { 
     /* foo */ 
    } 
#endif 

Die Eleganz ergibt sich aus:

  • Keine toten Code, wenn UPPER 0 ist
  • Vollständig portabel für jeden C-Compiler seit 1970-01-01
  • Einfach zu lesen und zu verstehen
0

Nicht eine gute Art der Codierung, aber löst die Aufgabe. g ++ eliminiert den toten Code, selbst wenn die Optimierung ausgeschaltet ist.

#define UPPER 0U 
int i; 
for(i = 0; &((char*)0)[i] < &((char*)0)[UPPER]; i++) { 
    /* foo */ 
} 
+0

Dies fügt eine Abhängigkeit von einem bestimmten C++ - Compiler zu C-Code hinzu. Das ist mindestens so hässlich wie der Code, der benötigt wird, damit das funktioniert wie angekündigt. – Jens

+0

Warum? Jeder C-Compiler sollte diese Konstruktion akzeptieren. BTW, auch das häufig verwendete OFFSET-Makro, das mit den gleichen Techniken implementiert wurde. – Serge

+0

Weil Sie von einem C++ - Compiler sprechen, nicht von einem C-Compiler, deshalb fügt er eine Abhängigkeit von C++ hinzu, je nachdem, was die Wörter vorschlagen. Wenn du es auf eine andere Weise meinst, ist es zumindest schwer zu verstehen. Die Hässlichkeit des Codes ist jedoch offensichtlich. Adress-Dereferenzierung von Arrays anstelle von plain int? Whoa! :-) – Jens

1

Es beseitigt Warnungen des Vergleichs von signed mit unsigned und verhindert, dass Compiler den Code zu optimieren.

#define UPPER 0U 
int i; 
volatile int u = UPPER; 
for(i=0; i < u; i++){ 
    /* foo */ 
} 

Getestet Kompilation mit gcc -Wall -Wextra myfile.c

+0

Es hat einen Nachteil: Es bricht die Optimierung, so dass 'i' nicht in ein Register eingetragen würde. – Serge

Verwandte Themen