Die C11 Standards sprechen über die Verknüpfung von Bezeichnern, aber es gibt keine offensichtliche Diskussion über die Regeln der Verknüpfung von Übersetzungseinheiten. Meine Frage wird aufgeworfen, indem ich zwei einfache Beispiele unter Verwendung von Klängen zusammenstelle.Welche Regeln gelten für die Verknüpfung von Übersetzungseinheiten in C11?
Hier ist mein erstes Beispiel, die zwei Erklärungen der gleichen Funktion hat, aber mit nicht kompatibelen Typen:
//testall.c
extern char myfun(void*);
int main(){
char a='c';
a=myfun(&a);
}
char myfun(char*c){
return *c;
}
Dann laufe ich den Befehl: $ Klirren -std = c11 testall.c
Und Klirren Berichte ein Fehler:
testall.c:9:10: error: conflicting types for 'myfun'
char myfun(char*c){
^
testall.c:2:17: note: previous declaration is here
extern char myfun(void*);
^
1 error generated.
Ich verstehe diesen Fehler, weil der Zeiger und der Zeiger Zeiger auf char sind inkompatible Typen.
Was mich verwirrt ist, dass, wenn ich die beiden Erklärungen in zwei verschiedene Übersetzungseinheiten trennen und sie dann verbinden in einem, Klirren keine Fehler meldet:
//test.c
extern char myfun(void*);
int main(){
char a='c';
a=myfun(&a);
}
// mylib.c
char myfun(char*c){
return *c;
}
Dann laufe ich diesen Befehl: $ Klirren -std = c11 test.c mylib.c.
clang kompiliert und verknüpft die beiden Übersetzungseinheiten, ohne einen Fehler oder eine Warnung zu melden.
Ich dachte, dass die Verknüpfung von zwei Übersetzungseinheiten den Regeln in Abschnitt 6.2.2 Verknüpfungen von Identifikatoren der C11-Standards folgt. Aber es scheint, dass dies nicht der Fall ist. Kann mir jemand helfen, es zu klären?
Nur weil Sie keine Diagnose bekommen, bedeutet das nicht, dass der Code legal ist! Herkömmlicherweise betrachtet ein Compiler nur eine Übersetzungseinheit gleichzeitig (so dass die Nichtübereinstimmung beim Kompilieren nicht erkannt werden konnte), und Typinformationen werden nicht in die Objektdatei übertragen, sodass der Linker die Nichtübereinstimmung nicht erkennen kann entweder. –
@NateEldredge Versuchen Sie, jeweils nur eine Datei auszuführen, anstatt beide in der Befehlszeile anzugeben. Doing 'gcc a.c b.c' kompiliert und verbindet in einem Schritt. C hat keinen Namen Mangling, so dass die Namen der Funktion für den Linker genau gleich aussehen. Was nun, wenn Sie drei Objektdateien mit 'myfun' haben? Sie erhalten einen Funktionsneudefinitionsfehler. Also klar, was du gesagt hast, kann nicht wahr sein. –
Obwohl 'gcc a.c b.c 'sowohl den Compiler als auch den Linker ausführt, handelt es sich um zwei separate Durchläufe, die keine anderen Informationen als die Objektdatei gemeinsam nutzen. Der Linker kann mehrere ** Definitionen ** desselben Symbols erkennen. Aber in Ihrem Beispiel ist die Funktion 'myfun' nur einmal ** in' mylib.c' definiert. Die Datei 'test.c' enthält eine ** Erklärung ** von' myfun', aber keine ** Definition **. Daher kein Fehler vom Linker. –