Makro verhält sich fehlerhaft bei GNU Compiler Linux u. Windows
-
Danke für die Unterstützung. Ich habe das genauso gesehen. Es ist der Code vom Kollegen, der auf Borland läuft und bei mir unter GCC eine Warning wirft. Der Kollege meinte, dass man den GCC in die Tonne treten sollte, wenn er nicht parallelisiert. Der Borland kann auch keine Inline-Funktionen. Der neue ANSI-konforme Code läuft übrigens perfekt.
-
kjesse schrieb:
Der Kollege meinte, dass man den GCC in die Tonne treten sollte, wenn er nicht parallelisiert.
Vielleicht sollte man Deinen Kollegen in die..... lassen wir das.
Wie kommt er darauf dass ein Compiler, ohne irgendwelche Erweiterungen, ohne dazu durch den Programmierer angewiesen worden zu sein, und ohne irgendwelche Threadfunktionen manuell benutzt zu haben, automatisch parallelisieren sollte?
Davon abgesehen, wieso sollte ausgerechnet eine parallele Ausführung sicherstellen, dass die vier Inkrementierungen in der richtigen Reihenfolge abgearbeitet werden? Der Witz an Parallelisierung wäre doch gerade, dass mehrere gleichzeitig abgearbeitet würden.
-
LordJaxom schrieb:
Wie kommt er darauf dass ein Compiler, ohne irgendwelche Erweiterungen, ohne dazu durch den Programmierer angewiesen worden zu sein, und ohne irgendwelche Threadfunktionen manuell benutzt zu haben, automatisch parallelisieren sollte?
Er meint wohl Instruction-Scheduling derart, dass parallele Pipelines bestmöglich ausgelastet werden. Nichts mit Threads.
Und er ist der Meinung, dass bei dieser Umordnung die Abhängigkeit der Inkrementierungen nicht richtig berücksichtigt wird. Da hätte er recht, wenn in C++ strenge Links-Nach-Rechts-Auswertung vorgeschrieben wäre, und wenn mehrfache Modifikationen zwischen Sequenzpunkten nicht explizit undefiniertes Verhalten hätten :p
-
Der Kollege hatte dann folgenden Code noch ausprobiert, der den gleichen Fehler beim Programmablauf bringt, aber keinerlei Warning mit GCC:
lpnadc->pu_buf = *lpnadc->R3P; lpnadc->R3P++; lpnadc->pu_buf=lpnadc->pu_buf<<8; \ lpnadc->pu_buf|= *lpnadc->R3P; lpnadc->R3P++; lpnadc->pu_buf=lpnadc->pu_buf<<8; \ lpnadc->pu_buf|= *lpnadc->R3P; lpnadc->R3P++; lpnadc->pu_buf=lpnadc->pu_buf<<8; \ lpnadc->pu_buf|= *lpnadc->R3P; lpnadc->R3P++; \
Hier wird zwar sequentiell gearbeitet, aber man hat das gleiche Problem mit dem Inkrementieren. Es kommt keine Warning, aber der gleiche Fehler beim Ausführen.
-
Ethon schrieb:
Wieso als Makro?Da ich schon weiß, welche Antwort kommen wird:
Der GCC kann so neuartige Standards wie C99. Da gibt es inline-Funktionen.Wie heißt es so schön in Effective C++: schon nur an Makro's zu denken ist schmerzhaft.
Und was spricht gegen eine Micki Maus Funktion ?
Makro's haben hübsche Seiteneffekte, da es bei Makro um ein dummen Ersetzungsvorgang handelt, und sind ebenfalls auch noch schwer zu debuggen. Sie sind daher nicht empfehlenswert.
#define min(a, b) (a < b) ? a : b //... c = min(++a, b); // ist äquivalent zu c = (++a < b) : ++a : b;
-
Ich benutze in meinen Programmen Inline-Funktionen, die auch noch schneller als Makros sind. Ich arbeite nur mit GCC auf Windows und Linux. Aber der Borland Compiler kann angeblich keine Inline-Funktionen im ANSI Standard.
-
Zum einen unterstützen weder Borland noch MSVC die neueren C-Standards (C99 aufwärts) und sollten demnach im C-Modus auch kein inline verstehen. Zweitens ist inline keine Garantie dass auch geinlined wird. Ergo: Kann viel gelabert werden, um Makros kommt man aber oft nicht herum.
-
Ich benutze in meinen Programmen Inline-Funktionen, die auch noch schneller als Makros sind. Ich arbeite nur mit GCC auf Windows und Linux. Aber der Borland Compiler kann angeblich keine Inline-Funktionen im ANSI Standard.
Hmm, ich glaube nicht das Makro's per se langsamer sind als Inline Funktionen. Bei Makros ersetzt der Präprozessor den Aufruf durch den Code während bei Inline Funktion der Linker den Aufruf ersetzt sofern das Kosten zu Nutzen Verhältniss stimmt (VC Compiler)
Aber, ist deine Anwendung so zeitkritisch das du auf ein paar Takte achten musst ?
Ich habe nämlich das Disassembly eines Testprojekts angeschaut und dort festgestellt das der Optimierer (alter VC Compiler) manchmal die Funktionen automatisch inlined ohne das ich explizite inline Funktionen hätte. Und seither stehe ich ein wenig kritisch gegenüber wenn es um Einsparungen von einigen wenigen Takten geht. Was nützt es dir wenn du hier und da ein paar Takte sparen willst wenn dein Optimierer das eh macht ? Alles unter der Vorraussetzung das du keine Sünden im Code hast.
Kann viel gelabert werden, um Makros kommt man aber oft nicht herum.
So zeitkritisch ???
Makro's funktionieren aber nur wenn man auf mögliche Seiteneffekte verzichtet. Funktionen sind da schöner, sie funktionieren auch mit Seiteneffekten. Sind also universeller. Und die schlechte Debuggingmöglichkeit ist meines Erachtens eh ein KO Kriterium.
-
Tim schrieb:
Zweitens ist inline keine Garantie dass auch geinlined wird.
Dann hat das aber auch einen guten Grund. Zum Beispiel, dass es ohne inline schneller ist. Der Compiler kann das beurteilen. Beim Makro ist er zum inline gezwungen und der Programmierer muss wissen, ob dies gerechtfertigt ist oder nicht.
-
kjesse schrieb:
Es kommt keine Warning, aber der gleiche Fehler beim Ausführen.
Was für ein Fehler? Du hast bisher nur geschrieben, dass das Verhalten anders als beim Sun oder Borland ist, und dass da irgendwas zweimal ausgeführt werden würde, ohne genauer zu beschreiben, was du eigentlich beobachtest.
Dazu möchte ich noch anmerken, dass in der Version die Casts fehlen. Sofern die im Ausgangscode notwendig (sprich: nicht nur Voodoo-Angstcode) waren, sind sie höchstwahrscheinlich auch jetzt noch notwendig. Im Zweifel poste die Definition des Strukturtyps von lpnadc.
-
Bitte ein Bit schrieb:
Wie heißt es so schön in Effective C++: schon nur an Makro's zu denken ist schmerzhaft.
(...)
Makro's haben hübsche Seiteneffekte, da es bei Makro um ein dummen Ersetzungsvorgang handelt, und sind ebenfalls auch noch schwer zu debuggen. Sie sind daher nicht empfehlenswert.
Makros sind subba!
Makros sind aber auch wie ein Hammer. Wenn man einen Nagel hat, ist ein Hammer subba! Und wenn man mit dem Hammer Schrauben in die Wand hämmert, dann ist deswegen nicht der Hammer schlecht.
-
Also Schrauben mit dem Hammer "schrauben" geht wunderbar und hält genau so gut wie geschraubt. :p
Anyway, Makros sind genial, nur als Funktionen missbraucht Mist.
-
Bitte ein Bit schrieb:
So zeitkritisch ???
Irgendwas ist immer am oberen Rand. Laufzeit, RAM, ROM. Das wechselt ständig. Die Frage ist ja, was die Funktionen machen deren Aufrufkosten man sparen will. Steckt dahinter richtig was, dann stört es kaum, steckt dahinter vielleicht nur ein Opcode, dann will ich dafür sicher keine Funktion aufgerufen haben.
SeppJ schrieb:
Tim schrieb:
Zweitens ist inline keine Garantie dass auch geinlined wird.
Dann hat das aber auch einen guten Grund. Zum Beispiel, dass es ohne inline schneller ist.
Ich kann mir gerade nicht so recht einen Fall konstruieren wo es schneller wäre eine Funktion nicht zu inlinen. Imho ist das eher ein Kompromiss aus Laufzeit und Codegröße. Und evtl. auch Stack.
-
Tim schrieb:
Ich kann mir gerade nicht so recht einen Fall konstruieren wo es schneller wäre eine Funktion nicht zu inlinen. Imho ist das eher ein Kompromiss aus Laufzeit und Codegröße. Und evtl. auch Stack.
Zu hohe Codegröße sprengt dir den Cache und geht dann auf die Performance.
-
Na da bin ich froh keinen Cache zu haben
-
Ich hatte im Dezember einen Kompressor geschrieben und dabei die Hashfunktion und den selbst geschriebenen memcmp zum byteweisen Vergleich durch "static inline" Funktionen ersetzt und mit einem 1 GByte File getestet. Inline war beim Komprieren schneller als Makro oder Funktionsaufruf, aber der Effekt war nicht riesig. Bei kleinen Dateien fällt das vermutlich nicht ins Gewicht.
-
Makros sind subba!
Makros sind subba und wenn diese auch noch optimal gelingen sind diese auch suboptimal...
Zu hohe Codegröße sprengt dir den Cache und geht dann auf die Performance.
Ist das jetzt sarkastisch gemeint ?Ich kann mir gerade nicht so recht einen Fall konstruieren wo es schneller wäre eine Funktion nicht zu inlinen. Imho ist das eher ein Kompromiss aus Laufzeit und Codegröße. Und evtl. auch Stack.
Im Fall wo es auf jedes (Kilo)Byte, jeden Takt ankommt, verstehe ich deine Argumente.
Aber auf etwas größeren Prozessoren und einem etwas guten Compiler würde ich von solchen Mikrooptmierungen eher abraten. Auf der einen Seite sind Makro's vielleicht etwas schneller, verbrauchen weniger Speicher (paar Bytes) und benötigen ein paar Takte weniger, sind aber dafür fehleranfälliger und kaum debuggbar. Funktionen haben die Makro-typsichen Fehler nicht, sind debuggbar, benötigen dafür aber ein wenig mehr Speicher und Takte.
Ich könnte auch genausogut argumentieren dass das Überprüfen der Speichergrenzen von Arrays ineffizient ist. Verbraucht auch ein paar Takte mehr und benötigt auch mehr Code.
Wer garantiert eigentlich das der Compiler/Optimierer nicht bereits solche Optimierungen ohne dein zutun macht? Der VC Compiler/Optimierer ist da böse, er fummelt auf höchster Optmierunsstufe schon erheblich am Code herum, behandelt Funktionen als inline, zerlegt for-Schleifen, ...
-
Bitte ein Bit schrieb:
Zu hohe Codegröße sprengt dir den Cache und geht dann auf die Performance.
Ist das jetzt sarkastisch gemeint ?Nein. Was lässt dich das vermuten?
-
Tim schrieb:
Zum einen unterstützen weder Borland noch MSVC die neueren C-Standards (C99 aufwärts) und sollten demnach im C-Modus auch kein inline verstehen. Zweitens ist inline keine Garantie dass auch geinlined wird. Ergo: Kann viel gelabert werden, um Makros kommt man aber oft nicht herum.
Macros sind der Spezialfall. Allgemein sollte man inline bevorzugen. Das heißt natürlich nicht, dass man niemals nie Macros verwenden darf. Aber allgemein sollte Macros vermeiden.
Ein guter Einsatzzweck ist zB die ganzen "forced inline" Varianten der verschiedenen Compiler portabel zu benutzen
#ifdef __GNUC__ #define FORCE_INLINE __attribute__((always_inline)); #elif ANDERERCOMPILER #define FORCE_INLINE foobarinline #else #error "no force inline" #endif
-
Nein. Was lässt dich das vermuten?
Der Sinn deines Satzes bezogen auf einen Otto-Normal-Entwicklungsrechner mit modernen Prozessor: Zu hohe Codegröße sprengt dir den Cache und geht dann auf die Performance.
Das würde ja implizieren das eine hohe Codegröße mit einem Performanceverlust einhergeht, was so nicht stimmt. Wenn ein Prozessor 4 kByte L1-Cache hat, bedeutet dann dass alle Programme > 4 kByte langsam sind ?
Was ist mit der Cache-Prediction ?