Frage

Sie sich das C-Programm besteht aus zwei Dateien,

f1.c:

int x;

f2.c:

int x=2;

Meine Lektüre des Absatzes 6.9.2 des der C99 Standard ist, dass dieses Programm zurückzuweisen. In meiner Interpretation von 6.9.2 wird der Variable x vorläufig in f1.c definiert, aber diese vorläufige Definition wird eine tatsächliche Definition am Ende der Übersetzungseinheit, und (meiner Meinung nach), sollte daher verhalten, als ob f1.c die Definition int x=0; enthielt.

Mit allen Compilern (und, was wichtig ist, Linker) Ich versuche, war in der Lage zu sein, das ist nicht, was passiert. Alle Kompilation Plattformen Ich habe versucht, die beiden oben genannten Dateien verlinken, und der Wert von x 2 in beiden Dateien.

Ich bezweifle, dass dies zufällig geschieht, oder einfach nur als „easy“ -Funktion zusätzlich zu dem, was der Standard erfordert. Wenn man darüber nachdenkt, bedeutet dies, gibt es spezielle Unterstützung im Linker für die globalen Variablen, die die explizit auf Null initialisiert, im Gegensatz keine Initialisierung haben. Jemand hat mir gesagt, dass die Linker-Funktion notwendig sein kann, Fortran sowieso zu kompilieren. Das wäre eine plausible Erklärung sein.

Alle Gedanken darüber? Andere Interpretationen des Standard? Die Namen der Plattformen, auf denen Dateien f1.c und f2.c verweigern miteinander verbunden werden?

Hinweis: Dies ist wichtig, weil die Frage im Zusammenhang mit der statischen Analyse auftritt. Wenn die beiden Dateien können sich weigern, auf irgendeiner Plattform verknüpft werden, sollte der Analysator beschweren, aber wenn jede Kompilation Plattform übernimmt es dann gibt es keinen Grund, sich um sie zu warnen.

War es hilfreich?

Lösung

Siehe auch Was sind externe Variablen in C . Dies wird in der C-Standard in informativen Anhang J als gemeinsame Erweiterung erwähnt:

  

J.5.11 Mehrere externe Definitionen

     

Es kann für die Kennung eines Objekts mehr als eine externe Definition sein, mit oder ohne die explizite Verwendung des Schlüsselwort extern; wenn die Definitionen nicht einverstanden ist, oder mehr als ein initialisiert wird, ist das Verhalten nicht definiert (6.9.2).

Warnung

Wie @litb zeigt sich hier, und wie es in meiner Antwort auf die Querverweise Frage angegeben, mehrere Definitionen für eine globale Variable führt zu undefinierten Verhalten verwenden, die die Art und Weise der Standard ist „etwas passieren könnte“ zu sagen. Eines der Dinge, die passieren kann, ist, dass das Programm verhält sich wie erwartet; und J.5.11 sagt etwa: „Sie mit etwas Glück vielleicht öfter, als Sie verdienen“. Aber ein Programm, das auf mehreren Definitionen einer externen Variable setzt - mit oder ohne ausdrückliches ‚extern‘ Schlüsselwort - ist kein streng konformes Programm und kann nicht garantiert überall zu arbeiten. Gleichwertig. Es enthält eine Fehler , die sich nicht zeigen kann oder

Andere Tipps

Es gibt etwas eine „gemeinsame Erweiterung“ die Norm genannt ist, wo Variablen mehrfach definiert, wie lange darf als die Variable nur einmal initialisiert wird. Siehe http://c-faq.com/decl/decldef.html

Die verlinkte Seite sagt, dies zu Unix-Plattformen relevant ist - ich denke, es ist das gleiche für c99 wie c89 - aber vielleicht hat es mehr Compiler angenommen worden, eine Art von einem De-facto-Standard zu bilden. Interessant.

Dies ist meine Antwort auf einen Kommentar von olovb zu klären:

Ausgang nm für eine Objektdatei von kompilierten „int x;“. Auf dieser Plattform werden Symbole mit einem ‚_‘, das heißt, die Variable x erscheinen als _x vorangestellt.

00000000 T _main
         U _unknown
00000004 C _x
         U dyld_stub_binding_helper

Ausgang nm für eine Objektdatei von kompilierten "int x = 1;"

00000000 T _main
         U _unknown
000000a0 D _x
         U dyld_stub_binding_helper

Ausgang nm für eine Objektdatei von kompilierten "int x = 0;"

00000000 T _main
         U _unknown
000000a0 D _x
         U dyld_stub_binding_helper

Ausgang nm für eine Objektdatei von kompilierten "extern int x;"

00000000 T _main
         U _unknown
         U dyld_stub_binding_helper

EDIT: Ausgabe von nm für eine Objektdatei von kompilierten "extern int x;" wobei x in einer der Funktionen tatsächlich genutzt

00000000 T _main
         U _unknown
         U _x
         U dyld_stub_binding_helper
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top