[switch/case] case-Ausdruck keine Konstante, obwohl typedef einer Konstante?
-
Um den Fehler zu verstehen, bedenke, dass zuerst die Module compiliert und danach zu einem Programm gelinkt werden.
In anwendung.cpp müssen die Variablen ME_TIME und ME_ALPHA zur compile-Zeit konstant sein, was aber nicht möglich ist, da sie als extern const deklariert sind und somit erst durch den Linker, der nach dem Compiler kommt, den Speicherbereich zugewiesen bekommen.
Vergl. z.B. auch den folgenden Code:
// main.cpp // Externes Linkage (extern ist hier Pflicht!). Siehe dazu auch weiter unten. extern const unsigned int global_var1 = 1; extern const unsigned int global_var2 = 2; void foo(unsigned int); int main() { cout << global_var1 << endl; foo(1); cout << endl; } // test.cpp // extern-Deklaration. (Siehe dazu ebenfalls weiter unten). extern const unsigned int global_var1; extern const unsigned int global_var2; void foo(unsigned int value) { switch(value) { case global_var1: // ist zur compile-Zeit nicht konstant, da externes Linkage. cout << "global_var1"; break; case global_var2: // dito. cout << "global_var2"; break; } }Desweiteren enthält dein geposteter Code-Snippet einen weiteren Fehler: Globale (bzw. im namespace) definierte und mit dem Zugriffspezifizierer const versehene Variablen haben in C++ internes (und nicht externes) Linkage. Willst du Globale, konstante Variablen mit externem Linkage definieren, schreibst du:
extern const T var = ...;(Wobei T der Typ und var der Bezeichner).
Gruß Caipi
-
Danke für die Antwort.

Also dann werden die Konstanten nicht wahrgenommen, weil sie in einer anderen Übersetzungseinheit (test.cpp) definiert werden und somit beim Übersetzen von anwendung.cpp nicht bekannt sind, _obwohl_ über die Variablen bekannt ist, dass sie konstant sind (Deklaration in test.h). Das Verhalten ist nicht ganz intuitiv.
Die Lösung ist jetzt, die Definitionen von test.cpp in test.h zu verschieben, wenn 's auch nicht sehr schön ist.Caipi schrieb:
Desweiteren enthält dein geposteter Code-Snippet einen weiteren Fehler: Globale (bzw. im namespace) definierte und mit dem Zugriffspezifizierer const versehene Variablen haben in C++ internes (und nicht externes) Linkage. Willst du Globale, konstante Variablen mit externem Linkage definieren, schreibst du:
extern const T var = ...;(Wobei T der Typ und var der Bezeichner).
Was meinst du damit?
Wenn ich extern verwende, werde ich es ja garantiert woanders definieren und wenn ich's gleich definieren kann/will, brauch ich das Schlüsselwort extern nicht. Die Begriffe externes/internes Linkage muss ich erstmal nachschlagen :).Grüsse,
don_basto.
-
extern const myEnum ME_TIME; extern const myEnum ME_ALPHA;so wie du es deklariert hast sind ME_TIME und ME_ALPHA variablen vom typ myEnum. und variablen sind natürlich nicht konstant. int-konstanten deklariert man in c++ am besten mit enum {}:
namespace myNS { enum myEnum { ME_TIME = 1, ME_ALPHA = 2 }; // .. }
-
@Konfusius:
Eine Variable ist variabel, klar. Aber sobald man ein const davorsetzt, ist sie es nach der Initaliserung nicht mehr.
enum hab ich nicht verwendet, weil ich dann bei der Verwendung casten müsste. Da ist mir typedef lieber.
-
Das Problem dabei ist, daß switch/case eine Compilezeit-Konstante benötigt - externe Konstanten stehen allerdings zur Compilezeit noch nicht fest (weil sie davon abhängen, welche anderen Module mit eingelinkt werden) und funktionieren deshalb an der Stelle nicht.
(PS: Wieso ist es dir so wichtig, daß deine Konstanten EXTERNE Bindung bekommen?)
-
Hab gelesen, dass man grudnsätzlich keine Variablen in den Headern definieren sollte, wegen Mehrdeutigkeiten beim Linken. Bei konstanten Variablen einfachen Typs (wie mein unsigned int) gibt's wohl trotzden keine Probleme. Deswegen habe ich jetzt die Definitionen in den Header übernommen, was funktioniert.
Im Header steht jetzt:const myEnum ME_TIME = 1; const myEnum ME_ALPHA = 2;
-
don_basto schrieb:
Hab gelesen, dass man grudnsätzlich keine Variablen in den Headern definieren sollte, wegen Mehrdeutigkeiten beim Linken.
Konstanten ohne explizite extern-Angabe bekommen automatisch interne Linkage, also bekommt der Linker sie überhaupt nicht zu sehen. Problematisch wird es nur mit "echten" Variablen, die doppelt dekalriert werden.
-
@don_basto
Darf ich mal fragen, was du für einen Compiler verwendest? Die Fehlermeldung ist nämlich total irreführend, denn nach case steht definitiv eine Konstante. Das Problem ist nur, case erwartet keine Konstante, sondern einen konstanten Ausdruck. Das ist ein kleiner, aber feiner Unterschied.
-
Ich verwende VC7.1 von MS.
-
Ah ok, kenne nur englische Versionen des Compilers. Und da heisst es
case expression not constant
was wiederum ok ist. Da hat wohl jemand bei der Übersetzung nicht aufgepasst und
case expression not a constant
gelesen.
