LINUX.ORG.RU

C extern variables


0

0

Собственно, возник следюущий вопрос: есть два файла *.c — main.c и notmain.c, а также заголовочный header.h.

notmain.c:

int var;
void initVar() { var = 5; }

main.c:

#include <stdio.h>
#include "header.h"

int main()
{
	initVar();
	var++;
	printf("var: %d\n", var1);
}

При этом выводится ответ 6 независимо от того, каким образом переменная var объявляется в header.h:

header.h:

int var; /* или extern int var */
void initVar();

единственное различие заметно при вызове nm для main.o:

для случая extern int var:

nm main.o
         U initVar
00000000 T main
         U printf
         U var

для объявления int var без extern:

 nm main.o
         U initVars
00000000 T main
         U printf
00000004 C var

Есть ли подвох?


Теперь создай notmain2.c, включающий header.h, слинкуй его с остальными объектниками и узнаешь ответ.

mannaz ()

В принципе подвоха почти нет. Хотя нормально в header-ах
лучше указывать extern.
Все работает потому, что С означает common - пошло от поддержки
Фортрана.
Просто все такие common переменные объединяются.
Однако в общем случае (например, старых реализациях gcc)
можно вляпаться в сообщение либо о повторном определении переменной,
либо (ну тут надо сыграть отдельно) о различии размеров объектов.

io ★★ ()
Ответ на: комментарий от mannaz

все по-прежнему работает.

notmain2.c:

#include "header.h"
void incrementVar() { var++; }

добавляю в header.h «void incrementVar();», вызываю ее из main.c. Все линкуется, программулька весело выдает ответ «7».

Corey ()
Ответ на: комментарий от io

Значит, в принципе, воможны оба варианта? Хотя предпочтительным является употребление extern?

Corey ()
Ответ на: комментарий от Corey

Сорри, по привычке воспринимал с точки зрения C++. В данном случае особой разницы нет.

mannaz ()

На верхнем уровне видимости все переменные объявляются как extern. Харбинсон и Стил советуют использовать для совместимости со старыми компиляторами в файлах ссылающихся на внешнюю переменную использовать extern без инициализации.

plambir ()
Ответ на: комментарий от nanoo_linux

После того как компилятор прошелся по тексту extern уже некая фикция.
Все (не auto) переменные (да и функции) либо попадают в какую-либо
из секций (типа .data, .bss и хитрее для подпрограмм) и аналогичное
определение фатально для процесса сборки, либо считаются «common»,
либо определяются как «внешний» соответственно неопределенный символ.
В первых 2 случая известно не только имя, но и размер, кроме того
предполагается инициализация 0-м по умолчанию.
Определения «int something;» и «int something=0;» - специальный
случай, каждый из вариантов, например, в различных версиях gcc,
мог попасть в .data, .bss или common секцию.
Особо много специальных случаев добавляет C++. Там в последних
релизах gcc даже код подпрограмм могут быть дублирован (template)
и при этом не порождать конфликта на этапе сборки.

io ★★ ()

Народ, я в панике! Вы чего, в школе не учились? Совсем не помните зачем нужно ключевое слово extern? Совсем никакого подвоха нет в приведенном коде, просто от слова extern в вашем примере совсем нет прока!

Приведу пример когда оно нужно:

test1.c

[code=c] #include <stdio.h> int main() { extern int x; printf(«%d\n», x); return 0; } [/code]

test2.c [code=c] int x = 5; [/code]

теперь компилируйте по-отдельности, и потом линкуйте. Вот зачем нужно ключевое слово extern!

Ну посмотрите что ли параграф 1.10 и 4.4 из K&R, примеры hoc из UPE.

В разделы 4.3, 4.8 Харбинсона-Стила следует смотреть только после того, как вы поняли на практике зачем нужно это слово.

anonymous ()
Ответ на: комментарий от anonymous

Спасибо за разъяснение. Но меня интересовал вариант объявления внешних переменных именно из заголовочного файла. А вообще, нормальная ли это практика — объявлять внешние переменные в заголовке? Или это делается непосредственно в том месте кода, где ожидается ее использование?

Corey ()
Ответ на: комментарий от Corey

Практика, как указывают Стил и Харбинсон, правильная. Там есть пункт 4.8.5, и в нем две рекомендации по использованию. Перепечатывать не буду их.

anonymous ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.