Глобальные переменные в файле заголовка
У меня есть 2 модуля (.c файлы) и один .h заголовочный файл:
file1.c:
#include <stdio.h>
#include "global.h"
int main()
{
i = 100;
printf("%d\n",i);
foo();
return 0;
}
file2.c
#include <stdio.h>
#include "global.h"
void foo()
{
i = 10;
printf("%d\n",i);
}
global.h
int i;
extern void foo()
Когда я делаю gcc file1.c file2.c, все работает отлично, и я получаю ожидаемый результат. Теперь, когда я инициализирую переменную "i" в файле заголовка, чтобы сказать "0" и снова скомпилировать, я получаю ошибку компоновщика:
/tmp/cc0oj7yA.o:(.bss+0x0): multiple definition of `i'
/tmp/cckd7TTI.o:(.bss+0x0): first defined here
Если я просто компилирую файл file1.c(удаление вызова в foo()) с инициализацией в файле заголовка, то есть gcc file1.c, все работает нормально. Что происходит?
Ответы
Ответ 1
Существует 3 сценария:
- с 2
.c
файлами и int i;
в заголовке.
- С 2
.c
файлами и int i=100;
в заголовке (или любом другом значении; это не имеет значения).
- С 1
.c
файлом и int i=100;
в заголовке.
В каждом сценарии представьте содержимое файла заголовка, вставленного в файл .c
, и этот файл .c
, скомпилированный в файл .o
, а затем связанный вместе.
Затем происходит следующее:
-
отлично работает из-за уже упомянутых "предварительных определений": каждый файл .o
содержит один из них, поэтому компоновщик говорит "ok".
-
не работает, потому что оба файла .o
содержат определение со значением, которое сталкивается (даже если они имеют одинаковое значение) - может быть только один с любым заданным именем во всех .o
файлы, которые связаны в данный момент времени.
-
работает, конечно, потому что у вас есть только один .o
файл и поэтому нет возможности для столкновения.
ИМХО чистая вещь будет
- поставить либо
extern int i;
, либо просто int i;
в заголовочный файл,
- а затем поставить "реальное" определение я (а именно,
int i = 100;
) в file1.c
. В этом случае эта инициализация используется в начале программы, и соответствующая строка в main()
может быть опущена. (Кроме того, я надеюсь, что именование является лишь примером, и не называйте глобальные переменные как i
в реальных программах.)
Ответ 2
Не инициализировать переменные в заголовках. Поместите объявление в заголовок и инициализацию в одном из файлов c
.
В заголовке:
extern int i;
В файле2.c:
int i=1;
Ответ 3
Вы не должны определять глобальные переменные в файлах заголовков. Вы можете объявить их как extern
в файле заголовка и определить их в исходном файле .c
.
(Примечание: В C, int i;
- предварительное определение, оно выделяет память для переменной (= это определение), если для этой переменной не найдено другого определения.)
Ответ 4
Dont определить varibale в файле заголовка, сделать объявление в файле заголовка (хорошая практика).. в вашем случае он работает, потому что несколько слабых символов.. Читайте о слабом и сильном символе.... link: http://csapp.cs.cmu.edu/public/ch7-preview.pdf
Этот тип кода создает проблему при портировании.