2016-10-17 6 views
-1

Ich habe untersucht, wann es möglich ist, Variablen zu mischen, die mit extern, static und keinem Speicherspezifizierer im globalen Gültigkeitsbereich deklariert sind. Die Ergebnisse haben mich ziemlich verwirrt.Deklarationen mit externem, statischem und keinem Speicherspezifizierer im globalen Gültigkeitsbereich

Das ist, was ich gefunden (jeder Absatz ist eine separate Übersetzungseinheit):

/* ok */ 
int x; 
int x; 

/* ok */ 
int f(); 
int f(); 

/* ok */ 
int x; 
extern int x; 

/* ok */ 
int f(); 
extern int f(); 

/* error: static declaration follows non-static declaration */ 
int x; 
static int x; 

/* ok (no warning) */ 
int f(); 
static int f(); 

/* ok */ 
extern int x; 
int x; 

/* ok */ 
extern int f(); 
int f(); 

/* ok */ 
extern int x; 
extern int x; 

/* ok */ 
extern int f(); 
extern int f(); 

/* error: static declaration follows non-static declaration */ 
extern int x; 
static int x; 

/* error: static declaration follows non-static declaration */ 
extern int f(); 
static int f(); 

/* error: non-static declaration follows static declaration */ 
static int x; 
int x; 

/* ok (no warning) */ 
static int f(); 
int f(); 

/* ok */ 
static int x; 
extern int x; 

/* ok */ 
static int f(); 
extern int f(); 

/* ok */ 
static int x; 
static int x; 

/* ok */ 
static int f(); 
static int f(); 

ich die gleichen genauen Ergebnisse mit gcc bekommen und clang aber ich kann ein Muster in nicht finden, was funktioniert und was nicht Arbeit.

Gibt es hier irgendeine Logik?

Was sagen die C-Standards zum Mischen globaler Deklarationen, die mit extern, static und keinem Speicherbezeichner deklariert wurden?

+1

Es gibt keine so etwas wie _ "no linkage" _ WRT globale Variablen. Der Standard (6.2.2 5) ist dabei ziemlich klar: _ "Wenn die Deklaration eines Bezeichners für eine Funktion keinen Speicherklassenbezeichner hat, wird ihre Verknüpfung genau so bestimmt, als wäre sie mit dem Speicherklassenspezifizierer extern deklariert worden. Wenn die Deklaration eines Bezeichners für ein Objekt Dateibereich und keinen Speicherklassenbezeichner hat, ist seine Verknüpfung extern. "_ –

+0

Anstatt C durch diesen testgesteuerten Ansatz zu lernen, sollten Sie sich vielleicht ein gutes Buch nehmen und darüber lesen. Und wenn Sie wirklich in der Spezifikation darüber wissen wollen, laden Sie einen Standardentwurf herunter (es ist kostenlos) und lesen Sie es selbst. Ab jetzt ist Ihre Frage einfach zu weit gefasst, IMO. – Downvoter

+0

Es gibt keine statische Verknüpfung und "statische" sowie "extern" sind Speicherklasse Spezifizierer in erster Linie. Verbindungsspezifikation ist ein Nebenprodukt. – Olaf

Antwort

1

Wenn Sie eine Kennung ohne das Schlüsselwort static definieren, ist es in der Objektdatei veröffentlicht und kann von anderen Modulen zugegriffen werden. Wenn Sie also diesen Bezeichner erneut ohne static in einem anderen Modul definieren, erhalten Sie einen Konflikt: zwei veröffentlichte Bezeichner.

Wenn Sie das Schlüsselwort static verwenden, dann gilt (der Großteil) der Rest nicht.

Das Problem ist der Unterschied zwischen Deklarieren der Kennung und definieren es. Der erste sagt "Es wird eine Kennung X mit diesem Typ geben". Der zweite sagt "Hier ist etwas, das ich anrufen werde X dieses Typs".

  • Mit Funktionen ist es einfach: bieten nicht den Körper, und es ist nur eine Erklärung. Stellen Sie den Körper, und es ist eine Definition zu. Sie können extern verwenden, um dies in einer Header-Datei explizit zu machen, aber da dies der Standardwert ist, ist das nicht üblich.

  • Mit Variablen ist es schwieriger. Einfach deklarieren die Variable definiert es auch - so können Sie es initialisieren, während definieren es. Wenn Sie möchten nurdeklarieren es, müssen Sie das Schlüsselwort extern verwenden - aber dann können Sie es auch nicht initialisieren. Du sagst: "Es wird eine Variable namens X" geben - also kannst du nicht die Wahnsinnigkeit haben, ihre Definition zu entscheiden!

Das warum in Header-Dateien alle Variablen explizit deklariert sein sollte entweder extern oder static:

  • Die erste ist üblich: Es wird eine gemeinsame Variable sein, dass jeder zugreifen kann. Vergessen Sie nicht, dass irgendwo in ein Modul, müssen Sie die tatsächliche Definition, ohne die extern Schlüsselwort, mit einem optionalen Initialisierungswert.
  • Die zweite ist selten: jedes Modul, das die Header-Datei enthält, wird seine eigene, nicht konfliktbehaftete Variable mit diesem bestimmten Namen haben. Der Compiler kann möglicherweise nicht Speicherplatz zuweisen (vor allem, wenn es eine Konstante ist) - aber wenn es Speicher reserviert, wird es in jedem Modul anders sein. Wieso würdest du das machen? Vielleicht brauchen die (erzwungenen) Inline-Funktionen dieser Header-Datei jedes Modul, um ihre eigene Kopie zu haben ...
0

Zunächst einmal gibt es nichts, das in Standard C "global" genannt wird, es ist ein oft missbrauchter Begriff, der mehrere verschiedene Dinge bedeuten kann.

Wenn Sie unter Dateibereich etwas deklarieren (was Sie "global" nennen) und keine Speicherklasse angeben, wird standardmäßig die externe Verknüpfung verwendet. Sie können im Dateibereich nichts ohne Verknüpfung angeben. Dies wird durch C11 6.2.2 festgelegt.

Variables (Hervorhebung von mir):

Wird die Erklärung einer Dateibereichskennung für ein Objekt oder eine Funktion der Speicherklassen Spezifizierer static enthält, die Kennung interne Bindung aufweist.

für einen Bezeichner mit den Speicherklassen Spezifizierer extern deklarierte in einen Bereich, in dem eine vorherige Erklärung dieser Bezeichner sichtbar ist, wenn die vorherige Anmeldung Verknüpfung interne oder externe spezifiziert, die Verknüpfung des Identifikators an dem spätere Deklaration ist die gleiche wie die Verknüpfung, die bei der vorherigen Deklaration angegeben wurde. Wenn keine vorherige Deklaration sichtbar ist, oder wenn die vorherige Deklaration keine Verknüpfung angibt, hat der Bezeichner eine externe Verknüpfung.

Funktionen:

Wird die Erklärung einer Kennung für eine Funktion keine Speicherklassen-Bezeichner hat, wird seine Verknüpfung genau bestimmt, als ob es mit der Speicherklasse Spezifizierer extern deklariert wurden . Wenn die Deklaration eines Bezeichners für ein Objekt den Dateibereich und keinen Speicherklassenspezifiziererhat, ist seine Verknüpfung extern.

Verwandte Themen