Frage

Wenn Refactoring einige #defines weg ich auf Erklärungen kam ähnlich dem folgenden in einer C ++ Header-Datei:

static const unsigned int VAL = 42;
const unsigned int ANOTHER_VAL = 37;

Die Frage ist, was für einen Unterschied, wenn überhaupt, wird die statische machen? Beachten Sie, dass mehrere Einbeziehung der Header aufgrund des klassischen #ifndef HEADER #define HEADER #endif Tricks nicht möglich ist (wenn es ankommt).

Ist der statische Mittelwert nur eine Kopie von VAL erstellt wird, falls der Header von mehr als eine Quelldatei enthalten?

War es hilfreich?

Lösung

Die static bedeutet, dass es eine Kopie von VAL für jede Quelldatei erstellt wird es in enthalten ist. Es bedeutet aber auch, dass mehrere Einschlüsse in mehreren Definitionen von VAL nicht führen werden, die zur Verbindungszeit kollidiert. In C, ohne die static müssten Sie, um sicherzustellen, dass nur eine Quelldatei VAL definiert, während die anderen Quelldateien erklärt es extern. Normalerweise würde man dies tun, indem sie definiert (möglicherweise mit einem Initialisierer) in einer Quelldatei und legen Sie die extern Deklaration in einer Header-Datei.

static Variablen auf globaler Ebene sind nur sichtbar, in der eigenen Quelldatei, ob sie dort ankamen über eine Include oder waren in der Hauptdatei.


Anmerkung der Redaktion:. in C ++ const Objekte weder mit den static noch extern Schlüsselwort in ihrer Erklärung sind implizit static

Andere Tipps

Die static und extern Tags auf Datei-scoped Variablen bestimmen, ob sie in anderen Übersetzungseinheiten zugänglich sind (das heißt andere .c oder .cpp-Dateien).

  • static gibt die variable interne Bindung, sie von anderen Übersetzungseinheiten zu verstecken. Allerdings können Variablen mit interner Verknüpfung in mehreren Übersetzungseinheiten definiert werden.

  • extern gibt die variable externe Bindung, um es sichtbar zu anderen Übersetzungseinheiten zu machen. Typischerweise bedeutet dies, dass die Variable muss nur in einer Übersetzungseinheit definiert werden.

Der Standard (wenn Sie nicht angeben static oder extern) ist einer jener Bereiche, in denen C und C ++ unterscheiden.

  • In C, Datei-scoped Variablen extern (externe Bindung) standardmäßig ist. Wenn Sie C verwenden, VAL ist static und ANOTHER_VAL ist extern.

  • In C ++ Datei-scoped Variablen static (interne Bindung) standardmäßig sind, wenn sie const und extern standardmäßig sind, wenn sie nicht sind. Wenn Sie C ++ verwenden, beide VAL und ANOTHER_VAL sind static.

Von einem Entwurf der C-Spezifikation :

  

6.2.2 Linkages von Identifikatoren   ...   -5- Wenn die Deklaration einer Kennung für eine Funktion keine Speicherklassen-Bezeichner hat, seine Verknüpfung   genau bestimmt wird, als ob es mit der Speicherklasse Spezifizierer extern deklariert wurde. Wenn   Die Deklaration eines Bezeichners für ein Objekt-Datei Umfang und keine Speicherklasse Spezifizierer,   seine Bindung ist extern.

Von einem Entwurf der C ++ Spezifikation :

  

7.1.1 - Speicherklasse Bezeich [dcl.stc]   ...   Ein Name in einem Namespace Umfang ohne Speicherklasse-Spezifizierer deklariert -6- hat externe Bindung, wenn es wegen einer früheren Erklärung interne Bindung hat und vorausgesetzt, es ist const nicht deklariert. Objekte erklärt const und nicht explizit extern interne Bindung erklärt haben.

Die statische bedeutet, dass Sie eine Kopie pro Datei zu erhalten, aber im Gegensatz zu anderen gesagt haben, es ist vollkommen legal, dies zu tun. Sie können dies einfach testen mit einem kleinen Codebeispiel:

test.h:

static int TEST = 0;
void test();

test1.cpp:

#include <iostream>
#include "test.h"

int main(void) {
    std::cout << &TEST << std::endl;
    test();
}

test2.cpp:

#include <iostream>
#include "test.h"

void test() {
    std::cout << &TEST << std::endl;
}

Ausführen dieses gibt Ihnen die folgende Ausgabe:

  

0x446020
  0x446040

const Variablen in C ++ interne Bindung haben. Also, static verwendet, hat keine Wirkung.

A. h

const int i = 10;

one.cpp

#include "a.h"

func()
{
   cout << i;
}

two.cpp

#include "a.h"

func1()
{
   cout << i;
}

Wenn dies ein C-Programm, würden Sie 'multiple Definition' Fehler für i erhalten (aufgrund externer Bindung).

Die statische Erklärung auf dieser Ebene des Codes bedeutet, dass der variabel in der aktuellen Übersetzungseinheit nur sichtbar ist. Dies bedeutet, dass nur Code innerhalb dieses Modul die Variable sehen.

Wenn Sie eine Header-Datei, die eine variable statische und dass die Header erklärt in mehreren C / CPP-Dateien enthalten, dann wird diese Variable „local“ zu diesen Modulen. Es wird für die N Orte N Kopien dieser Variable sein, die Header enthalten ist. Sie sind überhaupt nicht miteinander verwandt. Jeder Code innerhalb eines dieser Quelldateien werden nur die Variable verweisen, die in diesem Modul deklariert wird.

In diesem besonderen Fall das ‚statische‘ Schlüsselwort scheint keinen Nutzen bieten werden. Ich könnte etwas fehlt, aber es scheint keine Rolle -. Ich habe noch nie etwas getan gesehen vor

Wie bei inlining, in diesem Fall wird die Variable wahrscheinlich inlined, aber das ist nur, weil es const deklariert wird. Der Compiler könnte eher auf Inline-Modul statische Variablen, aber das ist abhängig von der Situation und der Code kompiliert wird. Es gibt keine Garantie, dass der Compiler ‚Statik‘ inline wird.

Das C Buch (kostenlos online) hat ein Kapitel über Verknüpfung, die die Bedeutung von ‚statischen‘ näher erklärt (obwohl die richtigen Antwort schon in anderen Kommentaren gegeben ist): http://publications.gbdirect.co.uk/c_book/chapter4/linkage. html

Um die Frage zu beantworten: „Ist die statische bedeutet nur eine Kopie von VAL erstellt wird, falls der Header von mehr als einer Quelldatei enthalten ist?“ ...

NO . VAL wird immer separat in jeder Datei definiert werden, die den Header enthält.

Die Standards für C und C ++ verursachen einen Unterschied in diesem Fall.

  

In C, Datei-scoped Variablen sind extern voreingestellt. Wenn Sie C verwenden, ist VAL statisch und ANOTHER_VAL ist extern.

Beachten Sie, dass moderne Linker über ANOTHER_VAL beschweren können, wenn der Header in verschiedenen Dateien (gleicher globaler Name definiert zweimal) enthalten ist, und würden auf jeden Fall beschweren, wenn ANOTHER_VAL auf einen anderen Wert in einer anderen Datei initialisiert wurde

  

In C ++ Datei-scoped Variablen sind statisch standardmäßig, wenn sie const sind, und extern standardmäßig, wenn sie nicht sind. Wenn Sie mit C ++, beide VAL und ANOTHER_VAL sind statisch.

Sie müssen auch der Tatsache Rechnung tragen, dass beide Variablen konst bezeichnet werden. Im Idealfall würde der Compiler immer wählen, um diese Variablen Inline und keine Speicher für sie ist. Es gibt eine ganze Reihe von Gründen, warum Speicherung zugeordnet werden kann. Die ich mir vorstellen kann ...

  • Debug-Optionen
  • Adresse in der Datei genommen
  • Compiler immer ordnet Speicher (komplexe const Typen können leicht nicht inlined, so wird ein Sonderfall für Grundtypen)

Sie können nicht eine statische Variable deklarieren, ohne es auch zu definieren (dies, weil die Speicherklasse Modifikatoren statische und extern gegenseitig ausschließen). Eine statische Variable kann in einer Header-Datei definiert werden, aber dies würde jede Quelldatei verursachen, die die Header-Datei enthalten eine eigene private Kopie der Variablen zu haben, was wahrscheinlich nicht der Fall ist, was beabsichtigt war.

Unter der Annahme, dass diese Erklärungen auf globaler Tragweite sind (das heißt nicht Membervariablen), dann:

statisch bedeutet 'interne Bindung'. da sie deklariert ist in diesem Fall const diese durch den Compiler optimiert / inlined werden kann. Wenn Sie die const weglassen, dann muss der Compiler Speicher in jeder Übersetzungseinheit zugeordnet werden.

Durch den Verzicht auf statisch die Verknüpfung extern in der Standardeinstellung. Auch hier haben Sie die const ness gespeichert - der Compiler kann Nutzung optimieren / inline. Wenn Sie die const Drop , dann werden Sie erhalten eine multiplizieren definierte Symbole Fehler beim Linken.

const Variablen sind standardmäßig statisch in C ++, aber extern C. Also, wenn Sie verwenden C ++ diese keinen Sinn, welche Konstruktion zu verwenden.

(7.11.6 C ++ 2003 und Apexndix C hat Proben)

Beispiel in vergleichen Compile / link Quellen wie C und C ++ Programm:

bruziuz:~/test$ cat a.c
const int b = 22;
int main(){return 0;}
bruziuz:~/test$ cat b.c
const int b=2;
bruziuz:~/test$ gcc -x c -std=c89 a.c b.c
/tmp/ccSKKIRZ.o:(.rodata+0x0): multiple definition of `b'
/tmp/ccDSd0V3.o:(.rodata+0x0): first defined here
collect2: error: ld returned 1 exit status
bruziuz:~/test$ gcc -x c++ -std=c++03 a.c b.c 
bruziuz:~/test$ 
bruziuz:~/test$ gcc --version | head -n1
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.5) 5.4.0 20160609

Static verhindert eine weitere Übersetzungseinheit aus externing diese Variable so, dass der Compiler kann nur „inline“ den Wert der Variablen, wo es verwendet wird, und nicht die Speicher für sie erstellen.

In Ihrem zweiten Beispiel der Compiler kann nicht davon ausgehen, dass eine andere Quelldatei nicht extern wird, so ist es tatsächlich irgendwo diesen Wert im Speicher ablegen muß.

Static verhindert, dass die Compiler aus mehreren Instanzen hinzufügen. Dies wird weniger wichtig, mit #ifndef Schutz, aber vorausgesetzt, der Header ist in zwei separaten Bibliotheken enthält, und die Anwendung verknüpft ist, würden zwei Instanzen einbezogen werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top