C die gleichen definierten globalen Variablen in verschiedenen Dateien
Lese ich dieser code von hier(in Chinesisch). Es ist ein Stück code, der zum testen von globalen Variablen in C. Die variable a
wurde in der Datei definiert t.h
die schon zweimal dabei. In der Datei foo.c
definiert struct b
mit einem Wert und einer main
Funktion. In main.c
- Datei definiert zwei Variablen, ohne initialisiert.
/* t.h */
#ifndef _H_
#define _H_
int a;
#endif
/* foo.c */
#include <stdio.h>
#include "t.h"
struct {
char a;
int b;
} b = { 2, 4 };
int main();
void foo()
{
printf("foo:\t(&a)=0x%08x\n\t(&b)=0x%08x\n
\tsizeof(b)=%d\n\tb.a=%d\n\tb.b=%d\n\tmain:0x%08x\n",
&a, &b, sizeof b, b.a, b.b, main);
}
/* main.c */
#include <stdio.h>
#include "t.h"
int b;
int c;
int main()
{
foo();
printf("main:\t(&a)=0x%08x\n\t(&b)=0x%08x\n
\t(&c)=0x%08x\n\tsize(b)=%d\n\tb=%d\n\tc=%d\n",
&a, &b, &c, sizeof b, b, c);
return 0;
}
Nach der Verwendung von Ubuntu-GCC-4.4.3 kompilieren, das Ergebnis ist, wie dies weiter unten:
foo: (&a)=0x0804a024
(&b)=0x0804a014
sizeof(b)=8
b.a=2
b.b=4
main:0x080483e4
main: (&a)=0x0804a024
(&b)=0x0804a014
(&c)=0x0804a028
size(b)=4
b=2
c=0
Variable a
und b
hat die gleiche Adresse in zwei Funktion, aber die Größe der b
geändert hat. Ich kann nicht verstehen, wie es funktionierte!
- Was ist deine Frage?
- Verwenden
%p
für Druck-Zeiger, auch sollten Siefoo
zu Ihrem Kopf. - Wenn Sie den Konflikt lösen wollen, deklarieren Sie var statisch.
- Es ist von coolshell (in Chinesisch), richtig?
- ja, ich lese diese aus coolshell aber nicht verstehen kann, ist klar, deshalb kopiere ich seine code hier zum diskutieren! Sorry für das! Ich habe Hinzugefügt-Anweisung am Anfang.
- Nein, ich bin nur neugierig, das ist alles. Ich glaube nicht, dass das ein problem ist, da Sie nicht kopieren Sie den gesamten Artikel. Ich persönlich mag es nicht, was erklärt, dass Artikel entweder. Also ich bin froh zu sehen, dass das problem hier besprochen.
- vielen Dank für Ihre Hilfe!
Du musst angemeldet sein, um einen Kommentar abzugeben.
Verletzen Sie den C ' s "one definition rule", und ist das Ergebnis undefiniert Verhalten. Die "one definition rule" wird offiziell nicht angegeben in der Norm als solche. Wir sind auf der Suche auf Objekte in unterschiedlichen source-Dateien (aka übersetzung-Einheiten), so dass wir den betroffenen mit "externen Definitionen". Die "eine externe definition" semantische dargelegt wird (C11 6.9 p5):
Was im Grunde bedeutet, Sie sind nur zulässig, um definieren ein Objekt in den meisten einmal. (Die sonst-Klausel können Sie nicht definieren, ein externes Objekt, wenn es nie benutzt wird überall im Programm).
Beachten Sie, dass Sie zwei externe Definitionen für
b
. Das eine ist die Struktur, die Sie initialisierenfoo.c
, und die andere ist die vorläufige definition inmain.c
, (C11 6.9.2 p1-2):Sie haben also mehrere Definitionen von
b
. Es ist jedoch ein weiterer Fehler, in dem von Ihnen definiertenb
mit verschiedenen Arten. Zunächst beachten Sie, dass mehrere Deklarationen für das gleiche Objekt mit externer Bindung ist erlaubt. Jedoch, wenn der gleiche name in zwei verschiedenen Quell-Dateien, der name bezieht sich auf das gleiche Objekt (C11 6.2.2 p2):C setzt eine strikte Beschränkung der Erklärungen auf das gleiche Objekt (C11 6.2.7 p2):
Da die Typen für
b
in Ihren Quell-Dateien, die eigentlich nicht passen, ist das Verhalten undefiniert. (Was ist ein kompatibler Typ ist im detail beschrieben in allen C11 6.2.7, aber im Grunde läuft darauf hinaus, dass die Typen müssen übereinstimmen.)So haben Sie zwei Mängel für
b
:Technisch gesehen, wird Ihre Erklärung von
int a
in beiden Quelldateien auch gegen die "one definition rule". Beachten Sie, dassa
hat externe Bindung (C11 6.2.2 p5):Aber aus dem Zitat von C11 6.9.2 früher, diese
int a
vorläufige Definitionen sind externe Definitionen, und Sie sind nur erlaubt, einer von denen aus dem Angebot von C11 6.9 oben.Den üblichen HAFTUNGSAUSSCHLÜSSE gelten für Undefiniertes Verhalten. Alles kann passieren, und das wäre auch das Verhalten, das Sie beobachtet.
Eine gemeinsame Erweiterung zu C ist, um zu ermöglichen, dass mehrere externe Definitionen, und ist beschrieben in der C-standard in den informativen Anhang J. 5 (C11 J. 5.11):
(Hervorhebung ist von mir.) Da die Definitionen für
a
Zustimmen, es ist kein Schaden vorhanden, aber die Definitionen fürb
nicht einverstanden. Diese Erweiterung erklärt, warum dein compiler beschwert sich nicht über die Anwesenheit von mehreren Definitionen. Aus dem Zitat von C11 6.2.2 der linker versucht zu versöhnen, die mehrere Referenzen auf das gleiche Objekt.Linkers in der Regel verwenden Sie eine der beiden Modelle für die Vereinbarkeit mehrere Definitionen der gleichen symbol, die in mehreren übersetzungseinheiten. Dies sind die "Gemeinsame Modell" und die "Ref/Def Model". Im "Gemeinsamen Modell", das mehrere Objekte mit dem gleichen Namen gibt, gefaltet in ein einzelnes Objekt in einer
union
Stil Weise, so dass das Objekt nimmt auf die Größe der größten in der definition. In der "Ref/Def Model", jeden externen Namen muss genau eine definition.Die GNU toolchain verwendet die "Gemeinsame Modell" by default, und eine "Entspannte Ref/Def Model", wo es erzwingt einen streng man die definition der Regel für eine einzelne übersetzungseinheit, aber beschwert sich nicht über die Verstöße über mehrere übersetzungseinheiten.
Den "Gemeinsamen Modell" unterdrückt werden kann, die in der GNU compiler mithilfe der
-fno-common
option. Wenn ich getestet auf meinem system, es verursacht "Strict Ref/Def Model" Verhalten bei code-ähnlich wie bei Ihnen:ich persönlich finde die Letzte Warnung ausgestellt von der linker sollte immer vorhanden sein, unabhängig von der Auflösung-Modell für mehrere Objekt-Definitionen, aber das ist weder hier noch dort.
Referenzen:
Leider kann ich nicht geben Ihnen einen link zu meiner Kopie des Standard C11
Was sind
extern
- Variablen in C?Die "Beginner' s Guide to Linkers"
SAS-Dokumentation auf Externe Variablen Modelle
Formell illegal ist, definieren Sie die variable (oder Funktion) mit externen Verknüpfung mehr als einmal. So, vom formalen Standpunkt aus das Verhalten des Programms ist undefiniert.
Praktisch, ermöglicht mehrere Definitionen der gleichen variable mit externer Bindung ist eine beliebte compiler-Erweiterung (eine gemeinsame Erweiterung, erwähnt als solche, die in der Sprachspezifikation). Allerdings, um richtig verwendet zu werden, jede definition erklärt es mit dem gleichen Typ. Und nicht mehr als eine definition umfassen die Initialisierung.
Ihrem Fall nicht mit der gemeinsamen Erweiterung der Beschreibung. Dein code kompiliert werden, als Nebeneffekt, die gemeinsame Erweiterung, aber sein Verhalten ist noch nicht definiert.
Den Teil des Codes scheint zu brechen, die eine-definition-Regel auf Zweck. Es wird aufgerufen, nicht definiertes Verhalten, das nicht.
Über die Globale variable
a
: don ' T put definition einer globalen variable in einer header-Datei, da Sie aufgenommen werden, in mehreren .c-Dateien, und führt zu multiplen definition. Setzen Sie einfach Deklarationen in den header setzen und die definition in einem der .c-Dateien.In t ist.h:
In foo.c
Über die Globale variable
b
: nicht definieren, die es mehrfach verwendenstatic
zu begrenzen, die variable in eine Datei.In foo.c:
In main.c
b
hat die gleiche Adresse, da die linker beschlossen, den Konflikt zu lösen für Sie.sizeof
zeigt unterschiedliche Werte auf, da sizeof ausgewertet, bei compile-Zeit. In dieser Phase, die der compiler kennt nur eineb
(das definiert man in der aktuellen Datei).b
s in der gleichen Speicherstelle.Zur Zeit foo kompiliert wird, die
b
innerhalb des Bereichs ist, der zwei Ganzzahlen Vektor{2, 4}
oder 8 bytes, wenn ein sizeof(int) 4 ist.Wenn main kompiliert ist, wird b hat soeben erneut deklariert als
int
so eine Größe von 4 Sinn macht. Auch dort ist wahrscheinlich "padding bytes", fügte der struct nach "a", so dass der nächste slot (int) ist ausgerichtet auf 4-bytes Grenze.a und b haben die gleichen Adressen, denn Sie treten an den gleichen stellen in der Datei. Die Tatsache, dass b eine andere Größe spielt keine Rolle, wo die variable beginnt. Wenn Sie eine variable c zwischen a und b in einer der Dateien, die Adresse des bs abweichen würde.