почему работает следующая программа - PullRequest
7 голосов
/ 11 июня 2011

Я написал следующую программу

#include<stdio.h>
 main ()
{
        extern int i;
        printf("\n%d",i);
}
int i=30;

Я ожидал сообщение об ошибке, поскольку я инициализируюсь после main, но программа выдала мне вывод.

Ответы [ 5 ]

21 голосов
/ 11 июня 2011

Целью extern является то, что он говорит, что «где-то в проекте есть переменная типа int с именем i, которая может быть связана позже. Просто предположим, что она существует».

Вы можете определить i в совершенно отдельном файле .c, и он будет работать, пока вы связываете файлы .o вместе. Вот что extern делает .

Это похоже на то, как вы можете объявить функцию и использовать ее, даже если она определена в совершенно отдельном файле .c (или даже позже в том же).

Прочитайте главу в своей книге на C о extern.

8 голосов
/ 11 июня 2011

Поскольку символ, представляющий i, все еще присутствует в программном пространстве. Объявляя это «extern», вы говорите компилятору НЕ обязательно ожидать определения «i», прежде чем встретить его ... другими словами, вы явно говорите компилятору, чтобы он верил, что символ будет связан позже. .

По сути, это ничем не отличается от наличия определения функции в совершенно отдельной библиотеке и объявления ее extern в вашей основной. Порядок не важен, так как символ все еще будет связан в.

3 голосов
/ 11 июня 2011

Если вы хотите более подробно взглянуть на то, как осуществляется доступ к i из основного и когда он инициализируется, вы можете посмотреть пример вывода сборки. Как отмечено в комментарии ниже, это из одной цепочки инструментов (gcc / linux), но должно помочь дать хорошую картину. Он показывает, что я нахожусь в сегменте данных и инициализирован до выполнения main.

    .file   "test.c"
    .section    .rodata
.LC0:
    .string "\n%d"
    .text
.globl main
    .type   main, @function
main:
    pushl   %ebp
    movl    %esp, %ebp
    andl    $-16, %esp
    subl    $16, %esp
    movl    i, %edx
    movl    $.LC0, %eax
    movl    %edx, 4(%esp)
    movl    %eax, (%esp)
    call    printf
    leave
    ret
    .size   main, .-main
.globl i
    .data
    .align 4
    .type   i, @object
    .size   i, 4
i:
    .long   30
    .ident  "GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2"
    .section    .note.GNU-stack,"",@progbits
3 голосов
/ 11 июня 2011

Экстерьер - это то, что определено внешне для текущего модуля. Вы можете использовать extern в случае, если ваша декларация поступит позже, или даже если ваша декларация находится в каком-то другом файле, еще не встреченном.

[ЭКОНОМИЯ ВАМ -> строки ниже от Википедии]

Когда вы определяете переменную, вы говорите компилятору выделить память для этой переменной и, возможно, также инициализировать ее содержимое некоторым значением.

Когда вы объявляете переменную, вы сообщаете компилятору, что переменная была определена в другом месте.

Вы просто сообщаете компилятору, что переменная с таким именем и типом существует, но компилятору не следует выделять для нее память, поскольку это делается где-то еще.

Ключевое слово extern означает "объявлять без определения". Другими словами, это способ явного объявления переменной или принудительное объявление без определения.

Подробнее: http://wiki.answers.com/Q/What_is_the_use_of_extern_in_C#ixzz1OzrWVmAC

1 голос
/ 11 июня 2011

Я ожидал сообщение об ошибке, поскольку я инициализируется после основного b

Глобальные переменные (как и все переменные со статической продолжительностью хранения) инициируются до того, как код в main () начинает выполняться независимо от того, где в коде вы их определили.

...