Interner Typ einer Enum-Konstante
-
Ahoy, Leute.
Ich habe folgenden Code:/***************************************************************************** **Zeittyp einer Datei. Auf *nix-Systemen gibt es drei Typen fuer Dateien: **letzter Zugriff, letzte Modifikation und Statusänderung. *****************************************************************************/ enum FILES_COT { FILES_COT_A, FILES_COT_M, FILES_COT_C };
Hierbei handelt es sich eigentlich nur um einen bestimmten Wertebereich, den eine Reihe von Funktionen als Parameter übernimmt. Um undefiniertes Verhalten durch einen Fehler des aufrufenden Programmierers/durch eine Sicherheitslücke, die es eventuell erlaubt, das Argument zu verändern, zu verhindern, habe ich einen Check für diesen Typen definiert:
#define FILES_COT_IS_SANE(x) (FILES_COT_A<=(x) && (x)<=FILES_COT_C)
Wenn also ein Wert unter der ersten oder ein Wert über der letzten Konstante angegeben wurde, soll das Makro 0 zurückliefern.
Soweit sogut. Aber jetzt haut mir der GCC hierfür Warnungen raus:
Warnung: Vergleich eines vorzeichenlosen Ausdrucks >= 0 ist stets »wahr« [-Wtype-limits] Warnung: Vergleich eines vorzeichenlosen Ausdrucks >= 0 ist stets »wahr« [-Wtype-limits]
Der vom Präprozessor generierte Ausdurck sieht so aus:
if(!(FILES_COT_A<=(wobj->ifrt_ifc) && (wobj->ifrt_ifc)<=FILES_COT_C))
wobj->ifrt_ifc
ist vom enum-TypFILES_COT
:struct files_remove_on_time_t { /*...*/ const enum FILES_COT ifrt_ifc; /*...*/ }
Eventuell habe ich gerade einen kompletten Blackout, aber ich habe noch gelernt, dass der Typ der Konstanten eines Enums
int
ist.int
ist vorzeichenbehaftet. Ich habe keine Compileroption aktiviert, die dies ändern würde:gcc ./src/files.c -I include/ <ein paar vorkompilierte Header> -O2 -E
Mein Problem ist folgendes: ich dachte bisher, dass die Konstanten vom Typ
int
sind, und daher auch vorzeichenbehaftete (sprich, negative) Zahlen aufnehmen können. Dann würde der Check auf0<=-1
Sinn ergeben. Der Compiler scheint aber in diesem Moment da einfach0<=0xFFFFFFFF
zu sehen. Aber dann scheint der GCC das doch auch nicht so zu sehen ...#include <stdio.h> enum A { A_A, A_B, A_C }; int main(void) { enum A my_a=(-1); printf("%d\n",my_a); return 0; }
Kompiliert mit:
gcc enums.c -o enum -Wextra -Wall -Wimplicit -fstack-protector -Wunused-parameter
Gibt keinen Fehler/Warnung aus.
Könnte mich jemand erleuchten, wo mein Denkfehler liegt? Ich habe grad irgendwie ein Brett vor dem Kopf.
-
Was hat**
wobj->ifrt_ifc
**für einen Typ?
-
Scheiße, hatte vergessen, den zu erwähnen. Hatte ich aber schon geprüft, dass der keine automatische Typenkonvertierung macht:
struct files_remove_on_time_t { /*...*/ const enum FILES_COT ifrt_ifc; /*...*/ }
-
gcc-Eigenart einer Optimierung, weil dokumentiert aber konform zum Standard.
Normally, the type is unsigned int if there are no negative values in the enumeration, otherwise int.
https://gcc.gnu.org/onlinedocs/gcc-4.4.0/gcc/Structures-unions-enumerations-and-bit_002dfields-implementation.htmlDürfte sich beheben lassen z.B. durch
enum FILES_COT { DUMMYENUM = -1, FILES_COT_A, FILES_COT_M, FILES_COT_C };
-
Ach, wie nett. Das sind ja tolle Optimierungen, die genau dann zuschlagen, wenn man sicherstellen will, dass keine ungültigen Werte angegeben werden. *würg*
Danke dir. Der vorgeschlagene Workaround funzt auch - unelegant, aber was tut man nicht für diese Marodeure ...
-
dachschaden schrieb:
Ach, wie nett. Das sind ja tolle Optimierungen, die genau dann zuschlagen, wenn man sicherstellen will, dass keine ungültigen Werte angegeben werden. *würg*
Danke dir. Der vorgeschlagene Workaround funzt auch - unelegant, aber was tut man nicht für diese Marodeure ...
Inwiefern hindert dich diese Optimierung an der Prüfung auf ungültige Werte und inwiefern ist dieser Workaround hier überhaupt nötig? Wenn dir jemand eine -1 übergibt, schlägt schließlich die Prüfung auf Werte > FILES_COT_C an.
-
dachschaden schrieb:
Ach, wie nett. Das sind ja tolle Optimierungen, die genau dann zuschlagen, wenn man sicherstellen will, dass keine ungültigen Werte angegeben werden. *würg*
Danke dir. Der vorgeschlagene Workaround funzt auch - unelegant, aber was tut man nicht für diese Marodeure ...
Ich würde gcc die Optimierun auch erlauben und stattdessen die Warnung an dieser Stelle abschalten.
Geht das mit nem pragma?
Mfg Martin
-
Wenn man für Compiler portabel bleiben möchte, die keine
unsigned enums
haben.
-
DirkB schrieb:
Wenn man für Compiler portabel bleiben möchte, die keine
unsigned enums
haben.Deshalb würde ich die Prüfung drinnen lassen und die Warnung ignorieren odrr abschalten.
Mfg Martin