Hier ist der Inhalt von src1.c:
%Vor%Und hier ist der Inhalt von src2.c:
%Vor% Warum ist es nicht obligatorisch, die Funktion go
in src1.c
file nach dem Kompilieren unter Linux zu deklarieren?
Setzt der Compiler die go
-Funktionsdefinition von src2.c
datei über den Code der Hauptfunktion, so dass die Deklaration dann nicht erforderlich wäre?
Ich mache es so:
%Vor% So dass jeder, der sagt, es ist möglich, die Anzahl und Arten von Argumenten in Abwesenheit des Prototyps zu übergeben, ist falsch. Sie werden in diesem Fall zu int
s hochgestuft, müssen aber mit den in Definition angegebenen übereinstimmen.
Ich habe einige Tests durchgeführt und herausgefunden, dass selbst wenn es kompiliert wird ohne Fehler, es nicht richtig funktioniert.
src1:
%Vor%sr2.c:
%Vor%Letztendlich könnte die Antwort nur undefiniertes Verhalten sein.
Danke Maxim Skurydin
Es ist in der Tat nicht obligatorisch, einen Prototyp für eine Funktion vor der Verwendung zu haben, aber das ist eine Eigenart der frühen Tage von C.
Wenn kein Prototyp vorhanden ist, kann der Compiler die tatsächlichen Typen, die an die Funktion übergeben oder von ihr zurückgegeben werden, nicht überprüfen. Dies kann sehr schlimm sein, wenn die Verwendung und die Deklaration nicht übereinstimmen.
Wenn der Compiler keinen Prototyp für go
sieht, wenn go(b);
aufgerufen wird, nimmt er an, dass er den folgenden Prototyp int go(<any number of arguments can be there>)
hat. Die Standardargumentaktionen werden für die Argumente vor dem Funktionsaufruf ausgeführt. Wenn in einem anderen Übersetzungsmodul keine Funktion go
vorhanden ist, erhalten Sie natürlich einen Linker-Fehler.
Ab c99 Standard:
6.5.2.2 Funktionsaufrufe
Wenn der Ausdruck, der die aufgerufene Funktion bezeichnet, einen Typ hat, der enthält keinen Prototyp, an dem Ganzzahl-Promotions ausgeführt werden Jedes Argument und alle Argumente, die den Typ float haben, werden in promoted doppelt. Diese werden als default argument promotions bezeichnet. Wenn die Anzahl der Argumente ist nicht gleich der Anzahl der Parameter, die Verhalten ist nicht definiert. Wenn die Funktion mit einem Typ definiert ist, der enthält einen Prototyp, und entweder endet der Prototyp mit einer Ellipse (, ...) oder die Arten der Argumente nach der Promotion sind nicht kompatibel mit den Typen der Parameter ist das Verhalten nicht definiert. Wenn die Funktion mit einem Typ definiert ist, der dies nicht tut Fügen Sie einen Prototyp und die Typen der Argumente nach dem Hochstufen ein sind nicht mit denen der Parameter nach der Förderung kompatibel, die Das Verhalten ist nicht definiert, mit Ausnahme der folgenden Fälle:
- Einer wurde befördert type ist ein vorzeichenbehafteter ganzzahliger Typ, der andere beworbene Typ ist der entsprechenden vorzeichenlosen Integer-Typ, und der Wert ist in darstellbar beide Typen;
- beide Typen sind Zeiger auf qualifizierte oder unqualifizierte Versionen eines Zeichentyps oder void.
6.3.1.1 Boolean, Zeichen und ganze Zahlen
2 / Wenn ein int alle Werte des ursprünglichen Typs darstellen kann, der Wert wird in einen int konvertiert; Andernfalls wird es in einen unsigned int konvertiert. Diese werden als ganzzahlige Werbeaktionen .48) bezeichnet. Alle anderen Typen sind
Aktualisierung:
Setzt der Compiler die Definition der go-Funktion aus der obigen src2.c-Datei der Code der Hauptfunktion, so dass die Deklaration dann nicht wäre benötigt?
Nein, es bringt nichts. Ein Zitat des obigen Standards besagt, dass kein Prototyp notwendig ist. Jede Datei wird unabhängig kompiliert, also wenn src1.c kompiliert wird, weiß sie nichts über src2.c und eine go
Funktionsdefinition darin.
Also jeder, der sagt, es ist möglich, die Nummer und die Arten zu übergeben von Argumenten in Abwesenheit von Prototyp ist falsch. Sie werden befördert zu intS in diesem Fall, muss aber mit denen in übereinstimmen Definition.
Es ist möglich und ich habe nach einer systemweiten Änderung ein paar obskure Bugs erlebt, die ohne irgendwelche Warnungen aus irgendeinem Grund gut kompiliert wurden (eigentlich ist es ein undefiniertes Verhalten).
Da jede * .c-Datei unabhängig voneinander kompiliert wird, gibt es jetzt die Möglichkeit, die Anzahl der Argumente und ihre Arten von go
-Funktion, die in einer anderen Übersetzungseinheit definiert sind, zu überprüfen. Wenn die Funktion mehr Argumente benötigt, die Sie angegeben haben, werden die "unbenutzten" Argumente mit einigen zufälligen Daten gefüllt. Sie sollten beachten, dass, wenn Argumente nicht übereinstimmen - es ist undefined Verhalten, was bedeutet, dass alles passieren kann.
Zunächst sollten Funktionsdeklarationen in Header-Dateien eingefügt werden. Jetzt eine Antwort auf deine Frage:
Wenn Sie beide Dateien kompilieren, findet der Linker zum Zeitpunkt des Linkens die Symboldefinition von go () in src2.o und löst somit die Symbolreferenz in der ausführbaren Datei auf. Dies ist der Grund, warum Ihr Programm funktioniert.
Sie versuchen, sizeof()
zu verwenden, das ein Kompilierzeitoperator ist, und es würde daher 1
ausgeben, da Sie es für einen Charakter ausgeben.
Sie übergeben auch einen Ganzzahlwert & gt; 255 an eine Variable char, dies würde einen Überlauf verursachen und t würde 1789modulo255 speichern.
Wenn Sie mit diesen beiden Quelldateien eine ausführbare Datei erstellen, wird die endgültige ausführbare Datei vorhanden sein
Definition von go()
also nicht nötig.
Aber es ist besser, declaration
in ein header file
zu setzen und diese Header-Datei dann in beide Quelldateien einzufügen
Hier ist Header-Datei someheader.h
%Vor%schließe es jetzt so ein
%Vor% in src1.c
und src2.c
Wenn der Compiler go()
in str1.c sieht, nimmt er an, dass die Funktion an anderer Stelle definiert ist. Es ist nur zu der Verknüpfungszeit, nach der der Linker sucht
die Definition von go()
.
Ich denke, Sie kompilieren die beiden Dateien separat und verknüpfen sie miteinander, was in Ordnung ist. Weil zur Verbindungszeit die Definition von go()
existiert.
Wenn Sie versuchen, str1.c ( gcc str1.c
im Gegensatz zu gcc -c str1.c
) separat zu kompilieren, erhalten Sie den Fehler, dass go()
nicht vom Linker gefunden wird.
UPDATE:
Selbst die implizite Deklaration durch den Compiler ist nicht standardkonform (seit C99) .
Technisch gesehen sollte jede Funktion einen Prototyp unabhängig von ihrem Rückgabetyp haben, wenn sie aufgerufen wird, bevor der Compiler seine Definition sehen kann. Die implizite Deklaration einer int-Rückgabefunktion ist nicht mehr gültig (gültig in C89) und wurde seit C99 (und C11) entfernt.
Obwohl die meisten Compiler immer noch nur eine Warnung ausgeben, ist dies kein Fehler. Aber wenn ein Compiler es ablehnt, zu kompilieren, weil der Funktionsprototyp nicht vorhanden ist, dann kann man sich nicht beschweren, da es nicht standardkonform ist.
Tags und Links c declaration