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

теперь у меня есть несколько сомнений по этому поводу:

  1. Почему не выводится:

    0 2

    1 0

  2. разве 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 используют следующие правила для работы с многозначными символами:

  1. несколько сильных символов не допускается.
  2. учитывая сильный символ и несколько слабых символов, выберите сильный символ.
  3. учитывая несколько слабых символов, выберите любой из слабых символов.

Итак, теперь мы можем спорить о том, что происходит в приведенном выше случае.

  1. среди int b = 2 и int b бывший сильный символ, в то время как последний слаб, поэтому b определяется значением 2.
  2. среди int a = 1 и int a, a определяется как 1 (то же самое рассуждение).

следовательно, вывод 1 2.


насколько я знаю: Выход будет 1 2 и 1 2, потому что вы определяете a и b как внешние переменные в основной функции.Таким образом, он будет пытаться принять значение из других файлов также. Что касается 2-го вопроса, я думаю, что компилятор принимает инициализированные значения переменной и объединяет их, потому что a и b определены как глобальная переменная в обоих файлах. Случай может быть разным, если оба были определены внутри функции. Любые предложения или другие материалы приветствуются.