Was ist die Idee hinter C99 inline?

8

Ich bin verwirrt über inline in C99.

Hier ist, was ich will:

  1. Ich möchte, dass meine Funktion überall inline wird, nicht nur in einer Übersetzungseinheit (oder einer Kompilierungseinheit, einer .c -Datei).
  2. Ich möchte die Adresse der Funktion konsistent sein. Wenn ich die Adresse der Funktion in einem Funktionszeiger speichere, möchte ich, dass die Funktion vom Zeiger aufrufbar ist, und ich möchte nicht, dass die gleiche Funktion in verschiedenen Übersetzungseinheiten dupliziert wird (grundsätzlich meine ich keine static inline ).

C ++ inline macht genau das.

Aber (und bitte korrigieren Sie mich, wenn ich falsch liege) in C99 gibt es keine Möglichkeit, dieses Verhalten zu bekommen.

Ich könnte static inline verwenden, aber es führt zur Duplizierung (die Adresse der gleichen Funktion in verschiedenen Übersetzungseinheiten ist nicht die gleiche). Ich möchte diese Vervielfältigung nicht.

Also, hier sind meine Fragen:

  1. Was ist die Idee hinter inline in C99?
  2. Welche Vorteile bietet dieses Design gegenüber C ++?

Referenzen:

  1. Hier ist ein Link, der sehr gut von C99 inline spricht, aber ich verstehe nicht warum. Ist das "nur in genau einer Compilierungseinheit" wirklich so schön?
    Ссылка
  2. Hier ist der Grund für C99 inline . Ich habe es gelesen, aber ich verstehe es nicht.
    Ist" inline "ohne" statisch "oder" extern "in C99 überhaupt sinnvoll?
  3. Ein schöner Post, der Strategien für die Verwendung von inline functions bietet.
    Ссылка

Zusammenfassung der Antworten

Wie bekomme ich C ++ inline behaviour in C99 (Ja, wir können)

head.h

%Vor%

src.c

%Vor%

main.c

%Vor%

Kompiliere es mit: gcc -O3 main.c src.c -std=c99
Überprüfen Sie die Baugruppe mit: gcc -O3 -S main.c src.c -std=c99 . Sie werden feststellen, dass my_max sowohl in call_and_print_addr() als auch in main() inline ist.

Das ist eigentlich genau die gleiche Anweisung wie in ref 1 und ref 3. Und was ist los mit mir?

Ich habe eine zu alte Version von GCC (3.4.5) zum Experimentieren benutzt, es gibt mir eine "multiple Definition von my_max " Fehlermeldung, und das ist der wahre Grund, warum ich es bin verwirrt. Schande.

Differenz zwischen C99 und C ++ inline

Tatsächlich können Sie das obige Beispiel mit g++ : g++ main.c src.c

übersetzen %Vor%

ist in C ++ redundant, aber in C99 notwendig.

Also, was macht es in C99?

Verwenden Sie wieder gcc -O3 -S main.c src.c -std=c99 , Sie werden in src.s so etwas finden:

%Vor%

Wenn Sie extern inline int my_max(int x, int y); ausschneiden und in main.c einfügen, finden Sie diesen Assemblercode in main.s .

Also, durch extern inline , sagen Sie dem Compiler, wo die wahre Funktion my_max() , die Sie an ihrer Adresse nennen können, definiert und kompiliert wird.

Schauen wir uns jetzt in C ++ um, wir können es nicht spezifizieren. Wir werden nie wissen, wo my_max() sein wird, und dies ist die "vage Verknüpfung" von @Potatoswatter.

Wie von @Adriano gesagt wird, kümmern wir uns die meiste Zeit nicht um dieses Detail, aber C99 beseitigt wirklich die Mehrdeutigkeit.

    
zsh 24.04.2014, 15:15
quelle

2 Antworten

6

Um C ++ - ähnliches Verhalten zu erhalten, müssen Sie jeder TU mit potenziell inlinierten Aufrufen eine inline -Definition geben und einer TU eine extern sichtbare Definition geben. Dies ist genau das, was Beispiel 1 in dem relevanten Abschnitt (Funktionsspezifizierer) des C-Standards veranschaulicht. (In diesem Beispiel wird die externe Sichtbarkeit rückwirkend auf eine inline -Definition angewendet, indem die Funktion extern danach deklariert wird: Diese Deklaration könnte in der .c -Datei nach der Definition in der .h -Datei erfolgen, was die übliche Verwendung darstellt auf den Kopf.)

Wenn das Inlining buchstäblich überall ausgeführt werden könnte, benötigen Sie nicht die Funktion extern . Nicht-inlinierte Aufrufe werden jedoch in Kontexten wie Rekursion und Referenzieren der Funktionsadresse verwendet. Sie können in einem gewissen Sinn die Semantik "immer inline" erhalten, indem Sie die extern -Teile weglassen, dies kann jedoch bei jedem einfachen Funktionsaufruf fehlschlagen, da der Standard nicht verlangt, dass ein Anruf inline wird, nur weil es keine Alternative gibt. (Dies ist das Thema der verknüpften Frage .)

C ++ behandelt dies mit dem Implementierungskonzept von "vage linkage"; Dies ist nicht im Standard angegeben, aber es ist sehr real und schwierig, innerhalb des Compilers. C-Compiler sollen einfacher zu schreiben sein als C ++; Ich glaube, das erklärt den Unterschied zwischen den Sprachen.

    
Potatoswatter 24.04.2014 15:31
quelle
3
  

Ich möchte, dass meine Funktion überall inline wird, nicht nur in einer Übersetzungseinheit (oder einer Kompiliereinheit, einer [.c] -Datei).

Mit Inline bitten Sie Ihren Compiler höflich, Ihre Funktion einzubinden (wenn es Zeit und Stimmung hat). Es hat nichts mit einer Kompilierungseinheit zu tun, im besten Fall kann es sogar in jeder einzelnen Call-Site inline sein und es wird nirgends eine Stelle haben (und sein Code wird überall dupliziert). Es ist Zweck der Inline, Geschwindigkeit zugunsten der Größe.

  

Ich möchte die Adresse der Funktion konsistent sein. Wenn ich die Adresse der Funktion in einem Funktionszeiger speichere, möchte ich, dass die Funktion vom Zeiger aufgerufen werden kann, und ich möchte nicht, dass die gleiche Funktion in einer anderen Übersetzungseinheit dupliziert wird. (Grundsätzlich meine ich keine 'statische Inline')

Wieder können Sie nicht. Wenn die Funktion inline ist, gibt es keinen Funktionszeiger darauf. Natürlich wird der Compiler eine Kompilierungseinheit brauchen, wo die Funktion bleibt (weil, ja, Sie brauchen vielleicht einen Funktionszeiger oder manchmal entschließt er sich, diese Funktion nicht in einer bestimmten Call-Site einzubinden).

Aus Ihrer Beschreibung geht hervor, dass static inline gut ist. IMO ist es nicht, ein Funktionskörper (wenn verwendet, siehe oben) in jeder Kompilierungseinheit führt zur Codevervielfältigung (und zum Problem im Vergleich von Funktionszeigern, weil jede Kompilierungseinheit ihre eigene Version von Ihrer hat) Funktion). Es ist hier, dass C99 etwas ziemlich Gutes getan hat: Sie deklarieren genau einen Platz, um den Funktionskörper zu platzieren (wenn und falls erforderlich). Compiler wird es nicht für Sie tun (wenn Sie sich jemals darum kümmern) und es gibt nichts mehr zu implementieren.

  

Was ist die Idee hinter Inline in C99?

Wählen Sie eine gute Sache (Inline-Funktionen), aber entfernen Sie Mehrdeutigkeit (jeder C ++ - Compiler hat seinen eigenen Job gemacht, wo der Funktionskörper bleiben muss).

  

Welche Vorteile hat dieses Design gegenüber C ++?

Ehrlich gesagt kann ich solch ein großes Problem nicht sehen (sogar Artikel, den Sie verlinkt haben, sind ziemlich vage über diesen Vorteil ). In einem modernen Compiler werden Sie kein Problem sehen und Sie werden sich nie darum kümmern. Warum ist es gut, was C getan hat? IMO, weil es eine Mehrdeutigkeit beseitigt hat, auch wenn - offen gesagt - ich bevorzuge, dass mein Compiler das für mich tut, wenn es mir egal ist (99,999%, nehme ich an).

Das heißt, aber ich kann falsch liegen, C und C ++ haben unterschiedliche Ziele. Wenn Sie C (nicht C ++ ohne Klassen und einige C ++ - Funktionen) verwenden, dann möchten Sie wahrscheinlich diese Art von Details behandeln, weil sie in Ihrem Kontext wichtig sind, so dass C und C ++ darüber auseinander gehen mussten. Es gibt kein besseres Design: nur eine andere Entscheidung für ein anderes Publikum.

    
Adriano Repetti 24.04.2014 15:48
quelle

Tags und Links