enum vs. #define
-
Squall3 schrieb:
Nabend,
Ich lese gerade mein C++ Buch und bin bei enum. Aber ich verstehe einfach nicht, worin der Unterschied zwischen normalen #define und enum besteht. Was ist so Vorteilhaft an enum??
#define wird vom Preprozesser behandelt. Das ist ein Programm was vor dem eigentlichen kompilieren aufgerufen wird und das Programm ist ziemlich dump. Es ersetzt einfach blind alles was auf das mit #define definierte Makro zutrifft. Dabei kümmert es sich nicht um Scopes, Namespaces oder was auch immer. Der Compiler bekommt am Ende den Quellcode mit der Ersetzung. Er sieht also auch nicht was du wolltest, sondern nur was passiert ist. Das kann zB bei Fehlermeldungen sehr verwirrend sein (weil der Compiler eben Fehlermeldungen zu einem Quellcode ausgibt, den du so gar nicht siehst)
enum dagegen ist ein Bestandteil der Programmiersprache und wird vom Compiler behandelt, mit allen Berücksichtigungen, die man normalerweise erwartet (Scopes, Namespaces etc.)
Daher sollte man #define versuchen zu vermeiden, wo man es vermeiden kann
Okay, bei enum kann man den Inhalt später noch ändern, aber da könnte ich auch genauso gut eine normale Variable deklarieren und einen Wert zuweisen, oder?
Du hast ja auch nur eine Variable deklariert
im Grunde hast du folgendes gemacht
[cpp]enum { elem1 = 1 };int var1 = elem1;[cpp]
-
hja schrieb:
..., woher weist Du dann welcher Code sich dahinter verbirgt? Richtig, Du mußt es nachschauen.
IDE erkennt und zeigt. Leider ist das in C++ so schwer möglich, ein weiterer Grund warum sich andere Sprachen derzeit auf dem Vormarsch befinden

hja schrieb:
Im OOP-Umfeld würde ich solche Lösungen wie Log4J jederzeit über so einen Macro-wisch-wasch vorziehen.
Da bringst du aber ein 1A-Beispiel für C++, Ausschnitt aus der Log4cxx-Doku:
// // Use these instead of calling Logger methods directly. // #define LOG4CXX_DEBUG(logger, msg) ... #define LOG4CXX_INFO(logger, msg) ... #define LOG4CXX_WARN(logger, msg) ... #define LOG4CXX_ERROR(logger, msg) ... #define LOG4CXX_FATAL(logger, msg) ...hja schrieb:
Lustig wirds wenn Du so ein Macro wie:
#undef TRUE
#define TRUE 0Wo habe ich behauptet, dass Makros eine gute Idee sind um Konstanten einzuführen. Die Verwendung von Makros deutet nur ganz einfach nicht auf ein schlechtes OOP-Design hin.
MfG SideWinder
Edits: Der Einsatz von Code-Tags wird immer schwieriger je später es ist

-
[quote="SideWinder]Wo habe ich behauptet, dass Makros eine gute Idee sind um Konstanten einzuführen. Die Verwendung von Makros deutet nur ganz einfach nicht auf ein schlechtes OOP-Design hin.
[/quote]eine Sache fällt mir zu dem Thema noch ein. Im Grunde untergräbt ein Macro einen Grundgedanken von OOP, die Kapselung von Sourcecode in einer Klasse, weil das Macro sich ähnlich einer globalen Variablen verhält und "von außen" Sourcecode in die Klasse bringt der obendrein Situativ anders sein kann. Dabei untergräbt das Makro Sicherheitsmaßnahmen wie privat, protected usw.
Jeder Mechanismus der die Datenkapselung verwaessert bzw aushebelt ist imho schelchtes OOP-Design.
PS: sorry, konnte nicht widerstehen

-
Hm da war doch auch noch was mit der Zeilenangabe bei Compilerfehlern.
#define abc 1 void f(std::string); int main() { f(abc); }Fehlermeldung:
Zeile 7: 1 ist kein string"Wo steht da 1?"
________________
enum( abc = 1} void f(std::string); int main() { f(abc); }Fehlermeldung: Zeile 7 enum abc ist kein string.
Dürfte gerade bei komplexeren sachen leichter zu erkennen sein.
-
benutz mal " "
und enums sind zahlen und keine strings
{ red, blue, yellow, grey = 100, black}
red = 0
blue = 1
...
grey = 100
black = 101bei dem define kommt eine textersetzung ....
also schreibst du rein abc(l), ist das ein string -.- ?
-
bei dem define kommt eine textersetzung ....
also schreibst du rein abc(l), ist das ein string -.- ?Nun ja, im Prinzip schon, doch std::string weiß das ohne weiteres einfach nicht

-
im prinzip eben nicht -.- das ist ein parameter
-
Mit define definierte Konstanten sind völlig Typlos, könnten also als fast alles geplant sein, wieso kann diese 1 dann nicht als Konstante vom Typ char geplant sein?
Schließlich handelt es sich bei charvariablen ebenso wie bei ints um einen integralen Datentyp, weswegen man strings natürlich auch aus integrale Zahlen zusammensetzen kann.
Gibt man z.B. char blub[] = { 72, 97, 108, 108, 111, 0 }; auf dem Bildschirm aus, erscheint dort "Hallo", ersetzt man hier char durch int erschiene auf dem Bildschirm "72971081081110"(je nachdem welchen Hinweis man dem Compiler zur Interpretation angibt).
Und diese 1 repräsentiert bei der (bei mir) standardmäßig gewählten Schriftart in der Konsole ein kleines Smilie :).Nur das "Problem" ist, die meisten Compiler erdreisten bzw erbarmen sich (je nachdem wie man das denn sehen möchte) eine integrale Zeichenliterale ohne typanzeigenden Zusatz so zu interpretieren, als SEI(!) diese integrale Zeichenliterale vom Typ int.
Sicherlich wird dies wohl deswegen so geregelt, weil dies wohl häufig so gedacht ist.Doch ändert dies nichts an der Tatsache, dass eine 1 bzw irgendwelche anderen Zahlen als integrale Zeichenliterle, im Prinzip durchaus einen String bilden können.
Die Angabe von (char)72 oder 'H' dürfte wohl äquivalent sein oO.
-
@hja
SideWinder schrieb:
Was ist an:
#define LOG(msg) Logger::log((msg), __FILE__, __LINE__);schlechtes OOP-Design?
MfG SideWindergar nichts.
auch an 5+5 ist kein schlechtes OOP-design zu erkennen.
(/me fühlt ein "java.lang.Math.oprator+(5,5)//nur so ist es OO" anklopfen)
vielleicht mag man herumspielen mit sachen wie#define LOG(msg) Logger::log(__FILE__<<__LINE__)<<msg;, um auch problemlos
LOG("cant open file "<<fileName);loggen zu können.
aber sooft man es dreht und wendet, beim logging kommen stets makros heraus.
-
volkard schrieb:
aber sooft man es dreht und wendet, beim logging kommen stets makros heraus.
Auch nur, weil es in C++ keinen Stacktrace gibt, um die Position im Code zu ermitteln
-
#define abc 1 void f(std::string); int main() { f(abc); }
du übergibst als string also übergibst du einen parameter
ersetz sieht es dann so aus:
void f(std::string); int main() { f(1); }verstehste nun ?
-
Wie wäre es wenn du einfach liest was ich schreibe?
Nur weil der Compiler da mecker, heißt das doch noch lange nicht, dass eine 1 kein String sein kann.
Sowohl int als auch char sind integrale Datentypen, beide speichern ganze Zahlen, hinter Buchstaben verstecken sich nunmal ganze Zahlen.Die integrale Zeichenliterale 1 (wie zu sehen ist ohne Datentypanzeigenden Zusatz) hat so lange keinen Typ, bis sie in einen bestimmten Typ gecastet wird und sei dies nur implizit.
#define abc 1 // <-- Ohne Datentyp void f(std::string); int main(int argc, char* argv[]) { f(abc); // <-- Daraus wird "f(1);" Die Datentyplose integrale // Literale(welche sowohl als int als auch als (z.B.) char oder // String interpretiert werden kann) wird hier in eine int- // konstante gecastet. // Bei den meisten Compilern ist es nunmal "voreingestellt", // dass integrale konstanten ohne typanzeigenden Zusatz // in int-konstanten GECASTET (<-- Vor dem Cast natürlich kein // eindeutiger int!) werden, // manche Leute nennen das implizitcast oO. // Soll heißen, überall wo während der Compilierung eine // integrale Literale steht, steht intern sowas wie (int)Literale. // Nunja, zumindest mindest lässt sich auf diese Weise // verdeutlichen worauf ich hinaus will. // Demnach lässt sich "f(1);" so LESEN, als WÜRDE // dort "f( (int)1 );" stehen // compilier das Programm mal mit folgenden Zeilen f(char(abc)); // char() zur Aushebelung des Implizit Casts char zeichen = abc; int zahl = abc; std::cout << zeichen << (char)zahl << std::endl; std::cout << (int)zeichen << zahl << std::endl; // Sollte es sich bei dir bei der 1 um ein nichtdruckbares Zeichen handeln, // versuch es einfach mal mit 72 oder sowas, ist garantiert was druckbares // drinne. return 0; }Soll heißen, eine 1, so ganz nackt im Quellocde, ist erst dann ein Int, wenn sie während der Compilierung einen impliziten Cast erfährt, wohlgemerkt - CAST, von "irgendwas" in int oO
-
Um dagegen zu halten schrieb:
volkard schrieb:
aber sooft man es dreht und wendet, beim logging kommen stets makros heraus.
Auch nur, weil es in C++ keinen Stacktrace gibt, um die Position im Code zu ermitteln
vor allem, weil man das loggen einigermaßen zentrall ausschalten können mag, ohne daß die parameter ausgewertet werden und funktionen aufgerufen werden.
-
EDIT: Is egal..
-
Kahino schrieb:
Nur weil der Compiler da mecker, heißt das doch noch lange nicht, dass eine 1 kein String sein kann.
Sorry das ich das sage: aber was Du meinst, ist sowas von unerheblich, das glaubst du garnicht. Weil nur das Zählt, was der ISO-C++-Standard und somit jeder weitestgehend konforme Compiler dazu sagt.
War jetzt hart für dich, aber das mußte einfach sein.

-
Kahino schrieb:
Nur das "Problem" ist, die meisten Compiler erdreisten bzw erbarmen sich (je nachdem wie man das denn sehen möchte) eine integrale Zeichenliterale ohne typanzeigenden Zusatz so zu interpretieren, als SEI(!) diese integrale Zeichenliterale vom Typ int.
Naja. Sie erdreisten sich, dem C++-Standard zu folgen, der das so fordert. In C sind BTW sogar Zeichenliterale wie 'H' vom Typ int.
-
Außerdem denke ich man kann doch in literalen auch den Typ angeben oder:
also so:#define ZWEI_LONG 2L #define ZWEI_UNSIGNED_LONG 2UL //oder #define (char)1
-
templäd schrieb:
Außerdem denke ich man kann doch in literalen auch den Typ angeben oder:
also so:#define ZWEI_LONG 2L #define ZWEI_UNSIGNED_LONG 2UL //oder #define (char)1^^
#define ONE_LONG 1L #define ONE_FLOAT 1.0f ...lol
MfG SideWinder
-
Sorry das ich das sage: aber was Du meinst, ist sowas von unerheblich
Brauchst dich dafür nicht entschuldigen, schließlich ist es unerheblich ob es unerheblich ist, sprechen wir doch über das Prinzip von Zahlen als typlose Abstrakta welche erst während der compilierung gecastet werden und als was sie zuvor so alles geplant sein könnten.
War jetzt hart für dich, aber das mußte einfach sein.
Tu mir leid, kann ich nicht nachvollziehen, hast du irgendwas gesagt, das meinen Aussagen widerspricht?
Naja. Sie erdreisten sich, dem C++-Standard zu folgen, der das so fordert.
Was hast du denn dagegen, dass integrale Literale ohne typanzeigenden Zusatz von Compilern standardmäßig in int-konstanten gecastet werden?
Ich hätte von den beiden angegebenen jeweiligen Extrema eher erbarmen statt erdreisten gewählt, wäre lästig ständig explizite casts für irgendwelche Tests mit Zahlen durchzuführen.Außerdem denke ich man kann doch in literalen auch den Typ angeben oder:
WÄRE durchaus möglich, ja

-
Kahino schrieb:
Naja. Sie erdreisten sich, dem C++-Standard zu folgen, der das so fordert.
Was hast du denn dagegen, dass integrale Literale ohne typanzeigenden Zusatz von Compilern standardmäßig in int-konstanten gecastet werden?
"gecastet" ist wohl das falsche Wort. Außerdem hab ich nichts dagegen, wie kommst du denn darauf? Ich habe nur deine Ausdrucksweise übernommen.