Extern в нескольких файлах и возможное двойное определение

Я запускал следующие коды, скомпилированные вместе как: gcc A.c B.c -o combined

Программа А:

#include<stdio.h>
int a=1;
int b;
int main()
{
extern int a,b;
fun();
printf("%d %d\n",a,b);
}

Программа Б:

int a;
int b=2;
int fun()
{
printf("%d %d\n",a,b); 
return 0;
}

При запуске "комбинированной" программы результат был:

1 2
1 2

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

  1. Почему не вывод:

    0 2

    1 0

  2. Разве a и b не определены дважды?

Пожалуйста, объясните это ясно, у меня было много проблем с пониманием внешности, и лишь немногие из этих сомнений продолжают появляться время от времени.

Заранее спасибо.

4 ответа

Решение

Итак, я отвечаю на свой вопрос через долгое время. Хотя утверждение:

int b; это декаларация и 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, а определяется как 1 (то же самое рассуждение).

Следовательно, выход 1 2,

Переменная может быть объявлена ​​много раз, если декларации согласуются друг с другом и с определением. Он может быть объявлен во многих модулях, включая модуль, в котором он был определен, и даже много раз в одном и том же модуле.

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

Теперь позвольте мне повторить определение extern, которое гласит: "внешняя переменная - это переменная DEFINED вне любого функционального блока"(пожалуйста, внимательно прочитайте слово, выделенное жирным шрифтом). Так что для Programe Aa есть определение, но b это просто объявление, поэтому extern будет искать его определение 'b', которое дано в Programe B. Так распечатать из Programe A является 1 2. Теперь давайте поговорим о Programe B которые имеют декларацию для a и определение для b так что ценится ценность a от programe A и значение b из текущего файла.

Потому что переменные здесь не определены дважды; они объявлены дважды, хотя. Функции берут значения из определения переменных, а не из объявления переменных.

Объявление вводит идентификатор и описывает его тип. Через объявление мы заверяем компилятору, что эта переменная или функция была определена где-то еще в программе и будет предоставлена ​​во время компоновки. Как, например, объявление:

extern int a;

Определение фактически создает / реализует этот идентификатор. Определение таково:int a=5; ИЛИ ЖЕ int a;

Просто прочитайте эту ссылку для дальнейшего использования.

есть и этот замечательный пост на stackru.

extern сообщает компилятору, что переменная определена снаружи, поэтому она смотрит за пределы функции и находит:

int a=1 в программе А и int b=2 в программе B

Для переменных AUTO:

int a;//both definition and declaration

Для получения дополнительной информации о классах хранения вы можете перейти по этой ссылке

int a вне главной или любой другой функции - это объявление (т. е. GLOBAL) только внутри любой функции, которая называется определением.

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

Другие вопросы по тегам