2014-01-17 4 views
3
void main() 
{ 
    extern int i; 
    printf("%d\n",i); 
} 
int i;//definetion 
int i=35;//definition 

В приведенном выше коде int i означает i=0; и int i=35 означает i=35., какое значение будет напечатано?

Итак, какое значение будет напечатано любым, почему компилятор не дает ошибку redefinition?

+4

Этот код не компилируется. И почему вы используете 'void main()' ?! –

+2

Существует только одно определение. – haccks

+0

@haccks: какой? –

ответ

3

В стандарте ansi они называют int x; «предварительным» определением.

Это то, что стандарт ANSI говорит:

Декларация идентификатора для объекта, который имеет файл объем без инициализатора, и без хранения класса спецификатора или с хранения класса спецификатора статического , представляет собой предварительное определение . Если единица перевода содержит одно или несколько предварительных определений для идентификатора, а единица перевода не содержит внешнего определения для этого идентификатора , то поведение точно равно , как если бы единица перевода содержала объявление области файла этого идентификатора области , с композит типа, как в конце блока перевода с инициализатором равным 0.

с примерами:

 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; /* $3.1.2.2 renders undefined, linkage disagreement */ 
    int i3; /* valid tentative definition, refers to previous */ 
    int i4; /* valid tentative definition, refers to previous */ 
    int i5; /* $3.1.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 */ 

в моем понимании, вы можете иметь столько предварительного défini одного и того же объекта, который вы хотите, и не более одного определения (с инициализатором). Если определения нет, предварительные определения превращаются в определение с инициализатором == 0 в конце файла.

Другими словами, напечатанное значение равно 35, поскольку имеется инициализатор.

+0

, если 'int i' означает' int i = 35', мы всегда можем заменить ' extern int i' с 'int i' –

+0

Не совсем. Если вы поместите 'int i' в заголовочный файл, он превратится в определение (и зарезервирует пробел для переменной) в конце каждого файла, включая этот заголовок, и вы столкнетесь с проблемой множественного определения во время связи. – Marian

+0

Что делать, если я помещаю 'int i' перед' void main() 'и удаляю' extern int i' из 'main()' .... тогда также работает код –

1

из 6.7.5:

«Определение идентификатора является декларацией того, что идентификатор: - для объекта, вызывает хранения должны быть зарезервированы для этого объекта; ...»

так как int i; и int i = 35; являются определениями (а также заявления, поскольку все определения являются заявления).

Разница заключается в том, что int i = 35; также имеет явный Инициализатор в то время как int i; неявно initilised к 0 (при условии глобальной длительности поэтому статического хранения), только если есть не внешнее определение:

от 6.2.9.2:

декларация идентификатора для объекта, который имеет файл сфера без инициализатора и без хранения класса спецификатора или с хранением класса спецификатором статическим, представляет собой неуверенно определение.Если единица перевода содержит одно или несколько предварительных определений для идентификатора , а единица перевода не содержит внешнего определения для этого идентификатора, то поведение точно такое же, как если бы единица трансляции содержала объявление области файла этого идентификатора области , с составной тип на конце единицы трансляции с инициализатором равного 0.

Обратите внимание, что эти предварительные определения не доступны в C++. (см. Приложение C1.2, пункт 3.1)

Следовательно, в этом случае будет напечатано значение 35, так как это значение, которое инициализируется i.