2015-10-18 8 views
19

Folgendes Programm beachten. Wird dies zu Kompilierungsfehlern führen?Was ist der Grund für die vorläufige Definition in C?

Auf den ersten Blick scheint der Compiler einen variablen Redefinitionsfehler zu haben, aber das Programm ist nach dem C-Standard perfekt gültig. (Siehe Live-Demo hier http://ideone.com/Xyo5SY).

Eine vorläufige Definition ist eine externe Datendeklaration, die keinen Speicherklassenspezifizierer und keinen Initialisierer hat.

C99 6.9.2/2

Eine Deklaration einer Kennung für ein Objekt, das ohne einen Initialisierer fi le Umfang hat, und ohne eine Speicherklasse spezifischen ER oder mit dem Speicherklasse spezifischen er statisch, stellt eine vorläufige Definition dar. Wenn eine Übersetzungseinheit eine oder mehrere vorläufige Definitionen für einen Identifier enthält und die Übersetzungseinheit keine externe Definition für enthält, die identisch ist, dann ist das Verhalten genau so, als ob die Übersetzung eine Dateibereichsdeklaration dieses Identifikators enthält der Verbundtyp ab Ende der Übersetzungseinheit, mit einem initializer gleich 0.

Meine Frage ist, was ist Gründe dafür, dass vorläufige Definitionen? Gibt es irgendeinen Gebrauch davon in C? Warum erlaubt C vorläufige Definitionen?

+2

Ich glaube nicht, dass es dafür keine wertvollen Gründe ist, weil C++ selbst hat es noch nie hatte, unter vielen andere Programmiersprachen. – edmz

Antwort

6

Vorläufige Definitionen wurden erstellt, um inkompatible Modelle vor dem C89 zu überbrücken. Dies wird in den C99 rationale Abschnitt 6.9.2 Externen Objektdefinitionen abgedeckt, die sagen:

Vor C90, Implementierungen weit in Bezug variierten Referenzierung Bezeichner mit interner Bindung zu übermitteln (siehe §6.2.2). Das C89 Komitee erfand das Konzept der vorläufigen Definition, um diese Situation zu behandeln. Eine vorläufige Definition ist eine Deklaration, die als eine Definition fungieren kann oder nicht: Wenn eine tatsächliche Definition später in der Übersetzungseinheit gefunden wird, fungiert die vorläufige Definition nur als Deklaration. Wenn nicht, fungiert die vorläufige Definition als tatsächliche Definition. Aus Gründen der Konsistenz gelten dieselben Regeln für Bezeichner mit externer Verknüpfung, obwohl sie nicht unbedingt erforderlich sind.

und Abschnitt 6.2.2 vom C99 Begründung sagt:

Die Definition Modell für Objekte mit externer Bindung verwendet werden sollte ein großes C89 Standardisierung Thema. Das grundlegende Problem war, zu entscheiden, welche Deklarationen eines Objekts Speicher für das Objekt definieren, und , die lediglich ein vorhandenes Objekt referenzieren. Ein damit zusammenhängendes Problem war ob mehrere Definitionen von Speicher zulässig sind, oder nur einer ist akzeptabel. Pre-C89-Implementierungen zeigen mindestens vier verschiedene Modelle , die hier aufgeführt in der Reihenfolge zunehmender restrictiveness:

+0

Wie können Sie den C & C++ Standard so gut kennen und verstehen? Du bist wirklich Genie. – Destructor

+0

@PravasiMeet Ich weiß es gut, weil ich viel Zeit damit verbringe, den Standard und die zugehörigen Dokumente und SO-Fragen zu lesen. Es geht nur um Übung und Erfahrung. Je mehr Erfahrung du hast, desto mehr interessante Probleme wirst du lösen und es baut sich einfach von dort auf. –

4

Hier ist ein Beispiel für einen Fall, in dem es sinnvoll ist:

void (*a)(); 

void bar(); 
void foo() 
{ 
    a = bar; 
} 

static void (*a)() = foo; 

/* ... code that uses a ... */ 

Der entscheidende Punkt ist, dass die Definition von foo-a zu beziehen hat, und die Definition von a muss foo verweisen. Ähnliche Beispiele mit initialisierten Strukturen sollten ebenfalls möglich sein.

+2

In diesem speziellen Fall könnten Sie die Notwendigkeit einer vorläufigen Deklaration vermeiden, indem Sie der ersten Zeile ein 'extern' hinzufügen (das ist nur eine Deklaration). Wo Sie wirklich die vorläufige Deklaration benötigen, ist, wenn Sie möchten, dass 'a'' statisch' ist (Dateiumfang) –

+0

@ChrisDodd: Ja, das habe ich verpasst. Ich werde es ändern. Vielen Dank. –

+0

Nein, es ist ein Funktionszeiger. –