2016-03-21 10 views
1

Я смущен и почему следующие работы:Отсутствие extern для переменной в C, но все же работает?

test.c

#include <stdio.h> 

int g; 
// ??? should be extern int g; ??? 

int main(){ 
    printf("%i\n", g); 
    return 0; 
} 

lib.c

int g = 3;

Почему я не получаю дубликат ошибки символа при компиляции? Я получаю ошибку, пытаясь сделать это на C++, так что это меня удовлетворяет. Однако в этом примере все компилируется и работает (т. Е. Успешно печатает 3) независимо от того, включен я или нет extern. Из чтения всех других вопросов о StackOverflow об extern в C все, кажется, говорят, что extern, используемый в переменной, объявляет переменную, но не определяет (то есть выделяет память) для нее. Но здесь, если я не использую extern, тогда я определяю две отдельные переменные, называемые g, поэтому должна быть какая-то повторяющаяся ошибка символа. Но нет, поэтому я очень смущен.

+0

Вы не включая 'lib.c '? – Carcigenicate

+0

Как вы его компилируете/связываете? –

+0

Это странно C (но не C++). Посмотрите здесь: http://stackoverflow.com/questions/3095861/about-tentative-definition, или здесь: http://ninjalj.blogspot.ch/2011/10/tentative-definitions-in-c.html –

ответ

1

N1570, 6.9.2 (курсив мой):

2 Декларация идентификатора для объекта, который имеет файл сферу без инициализатора и без хранения класса спецификатора или спецификатор класса хранения static, представляет собой предварительное определение .

4 Пример 1

 int i1 = 1;     // definition, external linkage 
     static int i2 = 2;    // definition, internal linkage 
     extern int i3 = 3;    // definition, external linkage 
     int i4;      // tentative definition, external linkage 
     static int i5;     // tentative definition, internal linkage 
     int i1;      // valid tentative definition, refers to previous 
     int i2;      // 6.2.2 renders undefined, linkage disagreement 
     int i3;      // valid tentative definition, refers to previous 
     int i4;      // valid tentative definition, refers to previous 
     int i5;      // 6.2.2 renders undefined, linkage disagreement 
     extern int i1;   // refers to previous, whose linkage is external 
     extern int i2;   // refers to previous, whose linkage is internal 
     extern int i3;   // refers to previous, whose linkage is external 
     extern int i4;   // refers to previous, whose linkage is external 
     extern int i5;   // refers to previous, whose linkage is internal 

int g; в вашем "test.c" является предварительное определение, давая g внешнее связывание (Смотрите примеры). Однако int g = 3; в «lib.c» имеет инициализатор, поэтому это не предварительное определение. В результате g в «test.c» относится к g в «lib.c», значение которого инициализируется 3.

Смотрите также: http://en.cppreference.com/w/c/language/extern