Extern в нескольких файлах и возможном двойном определении
я запускал следующие коды, скомпилированные вместе как:gcc A.c B.c -o combined
Программа A:
#include<stdio.h>
int a=1;
int b;
int main()
{
extern int a,b;
fun();
printf("%d %dn",a,b);
}
Программы B:
int a;
int b=2;
int fun()
{
printf("%d %dn",a,b);
return 0;
}
при запуске "комбинированной" программы выход был:
1 2
1 2
теперь у меня есть несколько сомнений по этому поводу:
-
Почему не выводится:
0 2
1 0
разве a и b не определены дважды?
пожалуйста объясните это ясно, у меня было много проблем с пониманием extern, и некоторые из этих сомнений продолжают приходить время от времени.
спасибо заранее.
4 ответов
переменная может быть объявлена много раз, пока заявления согласуются друг с другом и с определением. Он может быть объявлен во многих модулях, включая модуль, где он был определен, и даже много раз в том же модуле.
внешняя переменная может быть объявлена внутри функции. В этом случае необходимо использовать ключевое слово extern, иначе компилятор будет считать его определением локальной переменной, которая имеет другую область, время жизни и начальное значение. Это объявление будет видно только внутри функции, а не во всем модуле функции.
теперь позвольте мне повторить еще раз определение extern, в котором говорится: "внешняя переменная-это переменная определена вне любого блока, функции"(пожалуйста, внимательно прочитайте слово, данное в полужирный).
Так Programe A
a
есть определение, но b
- это просто объявление, поэтому extern будет искать свое определение "b", которое дано в Programe B
.Так что ... печать из Programe A
is 1 2
.Теперь давайте поговорим о Programe B
что есть декларация a
и определение b
так это priting значение a
С programe A
и стоимостью b
из текущего файла.
потому что переменные здесь не определены дважды; они объявляются дважды. Функции принимают значения из определения переменных, а не из объявления переменных.
объявление вводит идентификатор и описывает его тип.Посредством объявления мы заверяем complier, что эта переменная или функция была определена где-то еще в программе и будет предоставлена во время связывания. Как, например, декларация есть:
extern int a;
определение фактически создает/реализует этот идентификатор.
Определение :
int a=5;
или int a;
просто читать по этой ссылке для дальнейшего использования.
есть такая замечательная сообщение на stackoverflow тоже .
extern
сообщает компилятору, что переменная определена снаружи, поэтому она смотрит за пределы функции и там находит:
int a=1
в программу и int b=2
в программе B
для автоматических переменных:
int a;//both definition and declaration
для дальнейшего знания классов хранения вы можете по этой ссылке
int a
вне основной или любой другой функции является объявление (i.E GLOBAL) только внутри любой функции ее называют определением.
Итак, я отвечаю на свой собственный вопрос после долгого времени. Хотя утверждение:
int b;
- Это decalaration иint b = 2;
определение
правильно, но причина, которую все дают, не ясна.
если бы не было int b = 2;
, int b;
было определение, так в чем же разница?
разница заключается в том, что компоновщик обрабатывает несколько определений символа. Существует понятие слабости и сильные символы.
ассемблер неявно кодирует эту информацию в таблице символов перемещаемого объектного файла. Функции и инициализированные глобальные переменные получают сильные символы. Неинициализированные глобальные переменные получают слабые символы.
так Program A
, int a = 1
является сильным символом, в то время как int b;
является слабым символом, аналогично в Program B
, int b = 2
является сильным символом, и в то время как int a
слаб.
учитывая это понятие сильных и слабых символов, Компоновщики Unix используют следующие правила для работы с многозначными символами:
- несколько сильных символов не допускается.
- учитывая сильный символ и несколько слабых символов, выберите сильный символ.
- учитывая несколько слабых символов, выберите любой из слабых символов.
Итак, теперь мы можем спорить о том, что происходит в приведенном выше случае.
- среди
int b = 2
иint b
бывший сильный символ, в то время как последний слаб, поэтому b определяется значением 2. - среди
int a = 1
иint a
, a определяется как 1 (то же самое рассуждение).
следовательно, вывод 1 2
.
насколько я знаю: Выход будет 1 2 и 1 2, потому что вы определяете a и b как внешние переменные в основной функции.Таким образом, он будет пытаться принять значение из других файлов также. Что касается 2-го вопроса, я думаю, что компилятор принимает инициализированные значения переменной и объединяет их, потому что a и b определены как глобальная переменная в обоих файлах. Случай может быть разным, если оба были определены внутри функции. Любые предложения или другие материалы приветствуются.