Warum inlinet mein Compiler hier nicht?
-
typedef void (*fptr_t)(); void extfunc(const fptr_t *f); static inline void inlinable() {} void test() { const fptr_t f = inlinable; extfunc(&f); f(); }
Wenn ich das mit gcc 4.3.2 mit -O3 kompiliere, wird der Aufruf von f() am Ende nicht geinlinet, obwohl es sinnvoll wäre.
Prinzipiell ist gcc aber schon dazu imstande, Funktionen zu inlinen, die erst in einem Funktionspointer gespeichert und dann darüber aufgerufen werden; wenn ich extfunc(&f) durch extfunc(0) ersetze, tut er es. Und const beachtet er in solchen Fällen normalerweise auch; z.B. wird bei
void extfunc(const int *i); int test() { const int i = 29; extfunc(&i); return i + 13; }
direkt 42 zurückgegeben und nicht erst die Summe berechnet.
Habe ich irgendwas nicht verstanden und es gibt einen besonderen Grund dafür, dass der Compiler im ersten Programm die Funktion nicht inlinen kann/darf? Oder macht der gcc das nur einfach nicht und ich muss damit leben?
-
Ich sehe keinen besonderen Grund dafür, er dürfte es definitiv inlinen, da das Verhalten undefiniert ist, wenn extfunc den Funktionspointer verändert. Könnte ein Bug sein, muss aber nicht.
-
Du weisst die Adresse von inlineable einer Variablen zu. D.h. "inlineable" muss als Funktion existieren und kann nicht als "inline" behandelt werden. Warum sollte der Kompiler die Funktion erst als Funktion in den Binaercode schreiben und dann an anderer Stell doch anders behandeln? Ausserdem ist inline nur ein Vorschlag, kein muss fuer den Kompiler. Naja und das mit Parameter 0, was soll das denn aussagen? Bei 0 funktionierts, aber 0 ist auch keine Adresse auf eine reale Funktion.
-
knivil schrieb:
Du weisst die Adresse von inlineable einer Variablen zu. D.h. "inlineable" muss als Funktion existieren und kann nicht als "inline" behandelt werden.
Warum soll sie, selbst wenn sie als Funktion existieren muss, nicht auch geinlinet werden können?
Hier wird vom gcc die Funktion in test() auch geinlinet:
typedef void (*fptr_t)(); void extfunc1(fptr_t f); static inline void inlinable() {} void test1() { extfunc1(inlinable); } void test() { const fptr_t f = inlinable; f(); }
Warum sollte der Kompiler die Funktion erst als Funktion in den Binaercode schreiben und dann an anderer Stell doch anders behandeln? Ausserdem ist inline nur ein Vorschlag, kein muss fuer den Kompiler.
Dass der Compiler nichts inlinen muss, ist klar. Aber von einem optimierenden Compiler würde ich es in dem Fall erwarten.
Auf jeden Fall danke für die Antworten.
-
Aeh, ist das nicht ein sehr kuenstliches Beispiel? Wird test() nicht komplett weggeworfen, da keinerlei Seiteneffekte auftreten?
-
knivil schrieb:
Warum sollte der Kompiler die Funktion erst als Funktion in den Binaercode schreiben und dann an anderer Stell doch anders behandeln?
Unter der Prämisse, dass man Inline-Expansion durchführt, um sich den Aufruf-Overhead zu sparen: Warum sollte der Compiler sich davon beeinflussen lassen, ob die Funktion irgendwo nochmal nicht-expandiert zur Verfügung steht?
Naja und das mit Parameter 0, was soll das denn aussagen? Bei 0 funktionierts, aber 0 ist auch keine Adresse auf eine reale Funktion.
Das testet die Theorie, nach der der Compiler den Aufruf
extfunc(&f)
zum Anlass nimmt, seine Annahmen überf
fallen zu lassen und die Funktion über den Funktionspointer aufzurufen. Normales wissenschaftliches ArbeitenOb da 0 steht oder eine andere Funktion ist vollkommen gleichgültig, entscheidend ist, dass nicht
&f
übergeben wird.