2010-01-07 4 views
14

Ich habe eine Funktion, die auf Daten arbeitet (sagen wir mal, ein int), und ich möchte es an Ort und Stelle ändern, indem Sie einen Verweis auf den Wert übergeben. Als solche habe ich die Funktion: void myFunction(int *thing) { ... }. Wenn ich es benutze, nenne ich es so: myFunction(&anInt).Wird GCC inline eine Funktion, die einen Zeiger nimmt?

Da meine Funktion häufig aufgerufen wird (aber von vielen verschiedenen Orten), mache ich mir Sorgen um ihre Leistung. Der Grund, warum ich es in eine Funktion umstrukturiert habe, ist Testbarkeit und Wiederverwendung von Code.

Wird der Compiler in der Lage sein, die Funktion zu optimieren, so dass er direkt auf meine anInt Variable einwirkt?

Ich hoffe, Sie werden diese Frage in dem Geist, in dem es gefragt wird, nehmen (d. H. Ich bin nicht vorzeitig Sorgen um Optimierung, ich bin neugierig auf die Antwort). Ebenso möchte ich es nicht zu einem Makro machen.

Antwort

9

GCC ist ziemlich intelligent. Betrachten Sie dieses Code-Fragment:

#include <stdio.h> 

void __inline__ inc(int *val) 
{ 
    ++ *val; 
} 

int main() 
{ 
    int val; 

    scanf("%d", &val); 

    inc(&val); 

    printf("%d\n", val); 

    return 0; 
} 

Nach einem gcc -S -O3 test.c Sie werden die folgende relevante asm erhalten:

... 
call __isoc99_scanf 
movl 12(%rsp), %esi 
movl $.LC1, %edi 
xorl %eax, %eax 
addl $1, %esi 
movl %esi, 12(%rsp) 
call printf 
... 

Wie Sie sehen können, gibt es keine Notwendigkeit, ein asm-Experte sein, um die inc zu sehen() Aufruf wurde in eine Inkrementinstruktion umgewandelt.

+0

Zumindest mit GCC 4.4.2 muss es nicht einmal inline markiert werden! (Mit 'static' wird jedoch eine zusätzliche Kopie der Funktion in der generierten Binärdatei vermieden.) – ephemient

6

Es gibt zwei Probleme hier - kann der Code optimiert werden, und wird es. Das kann natürlich sein, aber der "Wille" hängt von der Stimmung ab, in der sich der Optimierer befindet. Wenn Ihnen das wirklich wichtig ist, kompilieren Sie den Code und schauen Sie sich die Assemblerausgabe an.

Auch scheinen Sie zwei Probleme zu verbinden. Eine Inlinefunktion hat ihren Körper effektiv an der Anrufstelle eingefügt. Ob Sie Zeiger verwenden oder nicht, ist weder hier noch dort. Aber Sie scheinen zu fragen, wenn der Compiler verwandeln kann:

int x = 42; 
int * p = & x; 
* p = * p + 1; 

in

x = x + 1; 

Dies ist viel schwieriger für die Optimierers zu sehen.

+0

Ich bin nicht ganz in der Phase, in der ich bereit bin, den Baugruppenausgang zu lesen! – Joe

+0

Re Ihrer letzten Bearbeitung mit 'x' und' p': Ja, das ist genau die Frage, die ich stelle. Ich weiß, es ist schwierig, darum habe ich gefragt, ob es möglich ist oder nicht! – Joe

+0

Wie gesagt, es ist möglich. Macht GCC das? Ich weiß es nicht. –

-1

Welche Compiler-Version verwenden Sie? Mit welchen Optionen? Auf welcher Plattform?

All diese Fragen beeinflussen die Antwort. Sie müssen den Code wirklich kompilieren und sich die Assembly ansehen, um sicher zu gehen.

1

Es wird (oder zumindest kann). Es gibt einige Gründe, warum die Funktion nicht inline sein kann - z. wenn Sie versuchen, auf einen Zeiger der Funktion zuzugreifen (Aufruf der Funktion durch Referenz - Sie greifen auf die Parameter per Referenz zu, was in Ordnung ist). Es kann andere Situation geben (statische Variablen? Unsicher)

Versuchen Sie, die Funktion mit "extern inline" zu deklarieren - dies verhindert, dass der Compiler den Standalone-Body ausgibt. Wenn die Funktion nicht eingebunden werden kann, wird ein Fehler ausgegeben.

+0

C99 sagt, dass "extern inline" dazu führt, dass Standalone-Objektcode generiert wird, und GCC folgt diesen ungeraden Regeln, wenn es in den C99-Modus versetzt wird. Andernfalls ist das Standardverhalten von GCC das, was Sie angegeben haben. (C89 sagt nichts, und das ist wohl die bessere Semantik.) – ephemient

2

Es sollte egal sein, ob das Argument ein Zeiger ist oder nicht.

Aber zuerst, wenn der Compiler sollte automatisch inline die Funktion, es muss statisch sein. Und es muss in derselben Compilierungseinheit enthalten sein. HINWEIS: Wir sprechen über C, nicht über C++. C++ Inline-Regeln unterscheiden sich.

Wenn es nicht möglich ist, die Funktion in der gleichen Kompilierungseinheit zu haben, dann versuchen Sie globale Optimierungen (überprüfen Sie die Dokumentation Ihres Compilers für Details).

C99 gibt Ihnen ein "Inline" -Schlüsselwort, genau wie in C++. Die hebt die Beschränkung auf die Übersetzungseinheit auf.

Hier sind einige further information.

+2

Da C89 überhaupt nichts über Inlining sagt, ist ein C89-Compiler sicherlich frei, jede Funktion einzufügen, die ihm gefällt. Natürlich könnte ein solches Programm nicht verlinken (was hier wirklich das Problem ist), aber ein Compiler mit einem integrierten Linker könnte dies durch Ausführen einer globalen Codeanalyse umgehen. –

+0

Also, ich denke, ein Compiler könnte automatisch nicht-statische Funktionen inline, wenn alle Dateien kompiliert und in einem einzigen Schritt in eine ausführbare Datei (nicht in eine Objektdatei oder Bibliothek) verknüpft werden. Nun, ok, aber es ist normalerweise nicht sehr praktisch;) Die Regel "Muss statisch sein" gilt auch sonst. – Frunsi

+1

Abhängig von den Einstellungen des Optimierers, der Größe der Funktion, der Häufigkeit der Aufrufe usw. wird GCC inline nicht statische Funktionen innerhalb der gleichen Kompilierungseinheit ausführen. Es wird weiterhin eine Nicht-Inline-Funktion erzeugen. – ephemient

18

Eine Möglichkeit, wenn die Funktion ist, um herauszufinden, inlined -Winline gcc-Option verwenden:

 
-Winline 
    Warn if a function can not be inlined and it was declared as inline. 
    Even with this option, the compiler will not warn about failures to inline 
    functions declared in system headers. 

    The compiler uses a variety of heuristics to determine whether or not to 
    inline a function. For example, the compiler takes into account the size 
    of the function being inlined and the amount of inlining that has already 
    been done in the current function. Therefore, seemingly insignificant 
    changes in the source program can cause the warnings produced by -Winline 
    to appear or disappear. 
+0

FANTASTISCHE Entdeckung –

+0

Obwohl es viele falsche Warnungen über Standard-Destruktoren ausspuckt> _ < –

-1

Dieses wie ein klassischer Fall der vorzeitigen Optimierung mir aussieht. Haben Sie wirklich wissen, gibt es ein Leistungsproblem hier? Es lohnt sich, Ihre wertvolle Zeit damit zu verschwenden, sich Sorgen zu machen. Ich meine, wirklich wissen? Wie hast du es gemessen?

An sich ist das nicht so schlimm, aber wenn Sie diese Einstellung über eine große Menge Code nehmen, können Sie einige schwerwiegende Schäden verursachen und eine große Menge an Entwicklungszeit und Wartungszeit ohne guten Grund verschwenden.

+0

Wie ich in der Frage sagte, mache ich mir keine Sorgen über Optimierung, ich versuche, mehr über die Sprache und GCC zu lernen. Ich glaube zwar an die Messung vor der Optimierung, aber ich denke, es ist sinnvoll, diese Dinge zumindest zu kennen. – Joe

0

Wenn Sie besorgt sind, dass der Compiler suboptimalen Code generiert und einen einfachen Werttyp ändern möchte, deklarieren Sie Ihre Funktion als int myFunction(int) und geben Sie den neuen Wert zurück.