Compiler Macros = teh evil
-
Also in VAX kein Problem, der kennt alle Makros und springt auch dort hin. Und beim Eingeben von der Memberfunktion hätte er auch gleich das sleep-Makro vorgeschlagen, dann hätte man stutzig werden müssen.
Aber am Ende des Tages: ja, Makros are evil!
Bis auf die Bedingte Kompilierung fällt mir sonst nicht ein, wofür sie nützlich sein sollten. Weil Bedingte Kompilierung ist einfach nur genial.
-
Weil Bedingte Kompilierung ist einfach nur genial.
Genial? Wo ist da die Genialität?
Bis auf die Bedingte Kompilierung fällt mir sonst nicht ein, wofür sie nützlich sein sollten.
TMP kann halt auch nicht alle Probleme lösen. Mit Bedacht (!) eingesetzt sind Makros nützlich (z.B. BOOST_FOREACH).
-
Irgendwer schrieb:
TMP kann halt auch nicht alle Probleme lösen. Mit Bedacht (!) eingesetzt sind Makros nützlich (z.B. BOOST_FOREACH).
Nein, Makros wie BOOST_FOREACH zeigt nur eines: es gibt eine Schwäche in der Sprache! Lies mal Stroustrups Buch, der schreibt das selber klipp und klar, das der Einsatz von Makros nur die Schwäche der Sprache zeigen.
Und BOOST_FOREACH sagt nur, das wir ein richtiges foreach als Schlüsselwort brauchen.
-
Was musste hier denn gesucht werden? Dass es ein Makro namens sleep gibt steht in der Fehlermeldung. Du benennst dein Ding um und gut. Oder hast du tatsächlich den entsprechenden Header (ich nehme an der kommt nicht von dir, da der Thread sonst komplett unsinning wäre) geändert? Wenn ja, wie lange hast du gebraucht es zu finden? 5 Minuten? Das wirft natürlich jedes Projekt um
Kurz: Ich sehe das Problem nicht.
-
Artchi schrieb:
Lies mal Stroustrups Buch, der schreibt das selber klipp und klar, das der Einsatz von Makros nur die Schwäche der Sprache zeigen.
Und BOOST_FOREACH sagt nur, das wir ein richtiges foreach als Schlüsselwort brauchen.
Dann warten wie mal bis zum nächsten C++-Standard, vielleicht kommt es dann
-
Tim schrieb:
Kurz: Ich sehe das Problem nicht.
Das Problem bekommst du spätestens dann, wenn du keine der beiden Definitionen ändern kannst, die dort aufeinanderprallen, weil sie beide in externen Quellen stehen, die du nutzen willst (ich erinnere mich düster an Kollisionen zwischen std::min/std::max und den gleichnamigen Makros in der MFC).
-
Tim schrieb:
Was musste hier denn gesucht werden? Dass es ein Makro namens sleep gibt steht in der Fehlermeldung. Du benennst dein Ding um und gut. Oder hast du tatsächlich den entsprechenden Header (ich nehme an der kommt nicht von dir, da der Thread sonst komplett unsinning wäre) geändert? Wenn ja, wie lange hast du gebraucht es zu finden? 5 Minuten? Das wirft natürlich jedes Projekt um
Kurz: Ich sehe das Problem nicht.
Nein, ich hab die lib komplett rausgeworfen. Das zu ersetzen war nicht schwer. Nur es zeigt, trotz Namespace und Fokus in einer Klasse kann so nen Makro dein Naming zerschiessen.
Umbennen ist ja auch nicht die Lösung. Nacher gibts irgendwo ein anderes Makro das viel gravierender ist.Das größte Problem daran ist, dass man Makros nicht in einen Namespace packen kann.
Btw:
Das Makro ist auch in den Headern von MySQL vorhanden. Das hab ich über VA herausgefunden.
-
CStoll schrieb:
Tim schrieb:
Kurz: Ich sehe das Problem nicht.
Das Problem bekommst du spätestens dann, wenn du keine der beiden Definitionen ändern kannst, die dort aufeinanderprallen, weil sie beide in externen Quellen stehen, die du nutzen willst (ich erinnere mich düster an Kollisionen zwischen std::min/std::max und den gleichnamigen Makros in der MFC).
Das Problem hast du aber grundsätzlich bei gleichen Symbolnamen im selben namespace. Sicher, man kann entsprechend andere Namespaces benutzen, aber ebenso kann man Makros ein entsprechendes prefix mitgeben. Also kein primäres Makro-Problem, oder? Dass sleep kein guter Name für ein Makro ist unterschreibe ich sofort. Aber das als "Makros sind böse"-Argument zu benutzen finde ich fragwürdig.
-
Das Problem hast du aber grundsätzlich bei gleichen Symbolnamen im selben namespace
Und wie soll das zustande kommen? Wer für den eigenen Namespace 2 gleiche Symbole definiert, ist selber schuld. Wer in den Namespace von anderen schreibt, ebenfalls. Ausserdem kann man das immer noch selber beheben, indem man einfach drumrum nen anderen packt.
-
Scorcher24 schrieb:
Wer für den eigenen Namespace 2 gleiche Symbole definiert, ist selber schuld. Wer in den Namespace von anderen schreibt, ebenfalls.
Vollkommen richtig, aber die gleiche Argumentation gilt auch für Makros. Makro scheisse benamt? Makro scheisse.
-
Tim schrieb:
Dass sleep kein guter Name für ein Makro ist unterschreibe ich sofort. Aber das als "Makros sind böse"-Argument zu benutzen finde ich fragwürdig.
Da muss ich zustimmen. Leider verwenden einige Bibliotheken Allerweltsnamen für Makros, das geht natürlich gar nicht. Aber das ist erstens kein Problem der Makros selbst, sondern ihrer Programmierer, und kann zweitens leicht umgangen werden. Wenn man es sauber macht wie z.B. Boost, ist die Scopeverschmutzung überhaupt kein Problem mehr.
-
Normalerweise stehen in einem namespace auch nur Funktionen, die mehr oder weniger zusammengehören, d.h. der Autor einer Bibliothek weiß recht genau, welche Überladungen er für einen Namen vorgesehen hat und wie er damit umgehen kann.
Das Problem mit einem Makro ist, daß es keine Rücksicht auf Namensräume, Scope oder Programmstruktur ersetzt wird - wenn du ein#define min(x,y)...
stehen hast, wendet der Präprozessor diese Textersetzung auf jedes Vorkommen des Bezeichners min an, egal ob sich dahinter eine Funktion im Namensraum einer Bibliothek, die Methode einer Klasse oder eine Variable verbirgt. (wenn du Glück hast, bekommst du eine Meldung wie Scorcher, daß die Parameter nicht stimmen, wenn nicht, siehst du nur einen Syntax-Fehler der nicht wirklich zu dem erkennbaren Code passt)PS: Und auf die inhaltlichen Probleme, die (selbst an den richtigen Stellen) durch die sture Textersetzung des Präprozessors auf dich zukommen können, will ich gar nicht erst eingehen.
-
Artchi schrieb:
Irgendwer schrieb:
TMP kann halt auch nicht alle Probleme lösen. Mit Bedacht (!) eingesetzt sind Makros nützlich (z.B. BOOST_FOREACH).
Nein, Makros wie BOOST_FOREACH zeigt nur eines: es gibt eine Schwäche in der Sprache! Lies mal Stroustrups Buch, der schreibt das selber klipp und klar, das der Einsatz von Makros nur die Schwäche der Sprache zeigen.
Und BOOST_FOREACH sagt nur, das wir ein richtiges foreach als Schlüsselwort brauchen.
Sieh es doch mal so: jedes Ding hat Fehler/Schwächen etc. Viele davon findet man erst "zu spät".
Und etwas, das und hilft einige dieser Schwächen im Nachhinein auszubügeln oder wenigstens abzuschwächen (Schwächen abschwächen, hihi), ist gut.
Also sind Makros gut.So einfach ist das. Zumindest für mich.
ps:
Gurte sind scheisse, sie zeigen nur die Unzulänglichkeiten des Fahrers/der Welt.
Muaha
-
Wer GNU
gcc
nutzt, kann den C-Präprozessorcpp
direkt aufrufen und sich den Code angucken, so wie ihn der Compiler zu sehen bekommt, mit allen ersetzten Makros, ohne Kommentare usw. Vielleicht hilft es weiter, wenn man nicht weiterkommt.
Ob so was auch bei anderen Compilern oder IDEs gibt...
-
Das Problem ist ja gelöst.
Ich fand es nur so genial exemplarisch für einen Foreneintrag, weil es genau die Art von Makro ist, die man eben nicht schreiben soll. Natürlich sind Makros was tolles wenn man sie sinnvoll einsetzt. Ich nutze sie ja auch. Aber ich prefixe meine Makros und gebe denen sinnvolle Namen, so dass Duplikate schwer werden.
-
Scorcher24 schrieb:
Das Problem ist ja gelöst.
Ich fand es nur so genial exemplarisch für einen Foreneintrag, weil es genau die Art von Makro ist, die man eben nicht schreiben soll.ACK
Natürlich sind Makros was tolles wenn man sie sinnvoll einsetzt. Ich nutze sie ja auch.
Na dann bin ich wieder beruhigt
Aber ich prefixe meine Makros und gebe denen sinnvolle Namen, so dass Duplikate schwer werden.
Sollte man auch machen. Es nicht zu machen wäre vergleichbar mit keine Namespaces zu verwenden, aber dafür schlechte und kurze Namen
-
Wie zum Beweis:
Soeben hat hustbaer sinnvolle Makros gezeigt beim TMP-Logarithmus.
http://www.c-plusplus.net/forum/285097-10
-
Nur für die Lulz:
MySQL Package, config-win.h, Zeile 213:
#define sleep(A) Sleep((A)*1000)
Ich meine, MySQL.. hallo? Die sollten es doch besser wissen :D.
Aber okay, es wurde alles dazu gesagt :p.
-
Scorcher24 schrieb:
#define sleep(A) Sleep((A)*1000)
Na, zumindest ist A sauber geklammert.
Ich schreibe eigentlich keine Makros bzw. war nie in einer Situation, wo ich sagen würde, jetzt bräuchte ich ein Makro... und, wenn ich so überlege, habe ich nie ein Makro gesehen, wo ich mich erstaunt und flüsternd "geil, ist das nützlich" zurücklehen konnte. Im Gegenteil, immer nur drübergestolpert, und stolpere immer wieder drüber.
Es gibt Sachen, bei denen man sich unfreiwillig fragt, warum hat sich eigentlich jemand für ein Makro entschieden, ein Makro, das irgendwie Information versteckt, nichts aussagt, einfach nur irgendwas vesteckt, wo man erstmal eine halbe Stunde lang suchen muss, um den Sinn zu verstehen.
Man hat z.B. eine Reihe von Funktionen:static void power_on(void) { ... } static void power_off(void) { ... } ...
und man fragt sich, wo werden sie eigentlich verwendet, denn es gibt keine Compiler-Warnung wie "unbenutzte statische Funktion" o.ä... dann schaut man erstmal weiter und wird irgendwann mal verzweifelt auf eine Zeile aufmerksam:
FANCY_MACRO(blabla, on, off);
dann sucht man nach FANCY_MACRO und findet so was:
#define FANCY_MACRO(a, b, c) \ struct power_struct power_##a \ { \ .on = power_##b, \ .off = power_##c \ }
oder ähnlich, weiß nicht genau, ob das so richtig ist, der Sinn davon ist, es gibt eine Struktur mit Funktionszeigern on und off und mit dem Makro wird eine Struktur angelegt und die Funktionszeiger initialisiert. Das ist irgendwie von hinten durch die Brust ins Auge.
Ich bin der Meinung, wenn Leute Makros schreiben, um sich die Tipparbeit zu ersparen - sollen sie andere für Programmierer geeignete Editoren benutzen, gvim oder emacs o.ä. Bei diesen Editoren, bei gvim zumindest, lässt sich die Tipparbeit schön automatisieren.
Wenn sie Makros schreiben, um den Code schlau zu machen, damit es kürzer aussieht oder was auch immer - das ist ungut, minus gut. Je schlauer der Code, desto schwieriger für andere, den Code zu verstehen, zu warten, zu debuggen...
-
abc.w schrieb:
#define FANCY_MACRO(a, b, c) \ struct power_struct power_##a \ { \ .on = power_##b, \ .off = power_##c \ }
oder ähnlich,
Fürchterlich.
Aber was ist mit diesen Makros?#define sin(x) sin((x)/180*PI) //bugfix, jetzt ist sin(90) endlisch wieder 1
#define cout cout<< //endlich geht cout "hello, world\n";
und mein Favorit
#define retrun return //gegen den üblichsten tippfehler