2014-12-29 7 views
5

sagen, dass ich eine Übersetzungseinheit file1.c, die erklärt, eine Datei-scope Variable wie so haben denn dasIst es gültig, ein externes globales als const zu behandeln, wenn die Definition nicht const ist?

int my_variable = 12; 

Dann in einer anderen Übersetzungseinheit file2.c, erstelle ich eine extern-Deklaration Variable, aber erklären ihn als const:

extern const int my_variable; 

Dies kompiliert und funktionieren mit gcc, mit -Wall -Wextra -ansi -pedantic. Der C89-Standard sagt jedoch Damit zwei qualifizierte Typen kompatibel sind, müssen beide die identisch qualifizierte Version eines kompatiblen Typs haben. Das Hinzufügen von const zu der Deklaration fügt eine Einschränkung hinzu, anstatt eine zu vermeiden. Ist das sicher und gültig? Was wäre die beste Vorgehensweise, um dies mit Header-Dateien einzurichten?

+2

Könnte der Compiler würde sich beschweren, wenn es andersherum war, wenn Sie den 'const'Qualifikator verwerfen. Aber ich bin mir nicht wirklich sicher. –

+2

Ich bin mir ziemlich sicher, dass [C - Zugriff auf eine nicht-const const-Deklaration] (http://stackoverflow.com/q/8051969/1708801) diesen Fall abdeckt. –

+0

Es lohnt sich wahrscheinlich, die genaue C-Standardversion anzugeben, auf die Sie sich beziehen. – Clifford

Antwort

5

Es ist eindeutig undefiniert, da die Deklarationen nicht übereinstimmen. Wie Sie festgestellt haben, sind const int und int nicht kompatible Typen. Eine Diagnose ist nur erforderlich, wenn sie im selben Bereich angezeigt werden.

Es entweder nicht sicher in der Praxis ist, sollten Sie

$ cat test1.c 
#include <stdio.h> 

extern const int n; 
void foo(void); 

int main(void) { 
    printf("%d\n", n); 
    foo(); 
    printf("%d\n", n); 
} 
$ cat test2.c 
int n; 
void foo(void) { ++n; } 
$ gcc -std=c99 -pedantic test1.c test2.c && ./a.out 
0 
1 
$ gcc -O1 -std=c99 -pedantic test1.c test2.c && ./a.out 
0 
0 

Gcc geht davon aus, dass n nicht durch foo() geändert wird, wenn die Optimierung, weil es die Definition von n annehmen kann aus einem kompatiblen Typ ist, so const .

Die Chancen stehen gut, dass Sie das erwartete Verhalten mit auch volatile -qualifying n in test1.c, aber so weit wie der C-Standard betrifft bekommen, ist dies noch nicht definiert.

Der beste Weg, die ich denken kann der Benutzer versehentlich modifiziert n zu verhindern, ist ein Zeiger auf const, etwas entlang

int my_real_variable; 
const int *const my_variable = &my_real_variable; 

oder vielleicht einige Makro

#define my_variable (*(const int *)&my_variable) 

Mit C99 zu erklären, my_real_variable kann über ein zusammengesetztes Literal vermieden werden:

const int *const my_variable_ptr = &(int){ 12 }; 

Es wäre legal, const hier wegzuwerfen (wie das int Objekt selbst ist nicht const), aber die Besetzung wäre erforderlich, versehentliche Änderung zu verhindern.

+0

Dies beantwortet die Frage gut; In diesem Beispiel habe ich gesucht. – Quackmatic

4

In diesem Fall erscheinen die Definition und die Deklaration in separaten Übersetzungseinheiten, so dass der Compiler keine Typ- oder Qualifier-Prüfungen durchführen kann. Die Symbole werden durch den -Linker aufgelöst und in diesem Fall scheint es, dass der Linker dieses Qualifikationsmerkmal nicht erzwingt.

Wenn die Definition und die Deklaration in der gleichen Übersetzungseinheit erscheinen; zum Beispiel, wenn Sie die extern Deklaration in eine Header-Datei und enthalten es in file1.c, dann würde ich mir vorstellen, dass der Compiler würde beschweren. Indem sie in separate Übersetzungseinheiten platziert werden, sieht der Compiler niemals beide, kann also die Prüfung nicht durchführen.

+0

Ich gehe davon aus, dass das Verhalten des Linkers in dieser Situation implementierungsspezifisch ist? In dieser Situation ist alles, was ich weiß, dass C Name Dekoration keine Aufmerksamkeit auf "const" (während C++ tut zum Beispiel.) – Quackmatic

Verwandte Themen