Zusammenhang von Compiler/Linker. Ein Beispiel



  • Hallo zusammen,

    ich beschäftige mich gerade mit den Zusammenhängen von Compiler und Linker.
    Angenommen, wir haben die Dateien a.c, b.c und a.h mit folgendem Inhalt:

    a.c:

    #include <stdio.h>
    #include "a.h"
    
    int main (void)
    {
        int x = 5;
        printf("f(x) = %i\n", f(x));
    
        return 0;
    }
    

    b.c:

    int f(int x)
    {
        return x + x;
    }
    

    a.h:

    #ifndef A_H
    #define A_H
    
    int f(int x);
    
    #endif
    

    Wenn ich nun via 'gcc a.c b.c' kompiliere/linke, erhalte ich korrekt die Ausgabe:

    "f(x) = 10"

    Die Frage ist nun, wieso? 🙂 Ich habe in der Datei b.c keinerlei Information hinterlassen, dass der Prototyp von f in a.h zu finden ist und dennoch wird das Programm korrekt "zusammengebaut". Sieht man hier den Linker in Aktion? Falls ja, wie "sicher" ist so ein Verhalten? Man kann sich vermutlich nicht darauf verlassen, dass der Linker in ähnlichen (aber möglw. komplizierteren) Situationen die Daten korrekt zusammensammelt oder doch?

    Beste Grüße
    Markus

    EDIT: Ich merke gerade, dass ich a.h in a.c noch nicht mal includieren muss und das Programm dennoch das gewünschte Ergebnis liefert - Magie? 🙂





  • pinwheel80 schrieb:

    Ich habe in der Datei b.c keinerlei Information hinterlassen, dass der Prototyp von f in a.h zu finden ist und dennoch wird das Programm korrekt "zusammengebaut".

    Es gibt einen Namen f mit external linkage, das reicht.

    Falls ja, wie "sicher" ist so ein Verhalten?

    Da es überhaupt keine Möglichkeit gibt, zu spezifizieren, welche Deklaration mit welcher Definition zusammenpassen soll, muss es wohl "sicher" sein. Oder was schwebt dir da vor?

    Man kann sich vermutlich nicht darauf verlassen, dass der Linker in ähnlichen (aber möglw. komplizierteren) Situationen die Daten korrekt zusammensammelt oder doch?

    Es geht alles nur nach dem Namen. Du deklarierst ein foo , dann setzt der Compiler an der Stelle eine Referenz auf ein Objekt namens foo ein. Du definierst ein foo , dann existiert diese Definition. Der Linker füllt einfach nur die Lücken aus, indem er die offenen Referenzen auf die bestehenden Definitionen umschreibt. Wenn dabei irgendwas nicht aufgelöst werden kann oder irgendwas mehrfach definiert wird, bekommst du die bekannten Linkerfehlermeldungen.

    EDIT: Ich merke gerade, dass ich a.h in a.c noch nicht mal includieren muss und das Programm dennoch das gewünschte Ergebnis liefert - Magie? 🙂

    Das ist dann eine implizite Deklaration. Der Compiler nimmt an, dass es eine Funktion f mit dem Rückgabetyp int und beliebigen Argumenten gibt. Und das stimmt dann auch besser.


Anmelden zum Antworten