#define scope в нескольких файлах
У меня есть основной файл:
main_a.c:
#define MAIN_A
#include <stdio.h>
#include "shared.h"
extern int i;
int main() {
printf("i is: %d\n", i);
return 0;
}
Я хочу использовать define в shared.h следующим образом:
shared.h
#if defined(MAIN_A)
# define A
#endif
Итак, я могу объявить переменную в зависимости от того, присутствует ли основной файл или нет, например:
shared.c
#include "shared.h"
#if defined(A)
int i = 1;
#else
int i = 0;
#endif
Я создаю его с помощью make файла, который выглядит так:
Makefile:
all : a
./a
a : main_a.o shared.o
gcc -o [email protected] $^
%.o : %.c
gcc -c $<
Однако это печатает
i is: 0
Теперь я задаюсь вопросом: почему возникает ошибка при компиляции совместно используемого модуля? Я знаю, что основной модуль скомпилирован первым, поэтому определение должно быть разрешено скомпилированным временем. Компиляция.
У меня есть подозрение, что препроцессор может запускаться в начале каждой сборки модуля, а не только в начале проекта. Если это правильно, есть способ скомпилировать более одного модуля за раз, чтобы использовать препроцессор, как я пытаюсь сделать выше?
Ответы
Ответ 1
Препроцессор запускается для каждого файла перед его компиляцией, т.е. один раз для main_a.c, а затем снова самостоятельно для shared.c. Когда shared.c скомпилирован, MAIN_A имеет значение undefined.
Препроцессор не может использоваться так, как вы пытаетесь, т.е. запоминать состояние в единицах компиляции.
Что вы можете сделать, так это определить имя (например, MAIN_A
), используя параметр компилятора -D
в вашем файле Makefile и протестировать это имя, используя препроцессор так же, как вы это делаете сейчас. Таким образом, определение выполняется на уровне проекта (в Makefile), а не на уровне единицы компиляции (в файле .c).
Ответ 2
Позвольте мне выполнить препроцессор здесь и развернуть все ваши макросы. В main.c
определяется MAIN_A
, поэтому A
определяется. Ничего не зависит от A
в main.c
, а i
- extern.
В shared.c
, MAIN_A
и тем самым A
являются undefined, а i
равно 0.
Короче говоря, препроцессор не может передавать информацию между единицами компиляции. Эта хорошая практика, потому что в противном случае программы быстро стали бы нечитаемыми, и вам придется перекомпилировать все единицы компиляции, когда одна единица изменится (поскольку символы могли быть изменены). Устраните проблему, установив i
явно в main
:
int main() {
i = 1;
}
Это более подробный, но также более понятный читателю. Если вы хотите инкапсулировать, определите функцию InitializeShared
. Если вы действительно хотите скомпилировать некоторый код как единый блок компиляции, сделайте один из файлов заголовочным файлом и #include
в другой.
Ответ 3
Да, вы правы, это совершенно разные единицы компиляции.
MAIN_A определяется только в main_a.c
Одна мысль, которая приходит на ум, - собрать файлы вместе, чтобы сделать один блок компиляции?
Ответ 4
Глобальное определение A
gcc main_a.c shared.c -DA
Ответ 5
Определяет почти ту же работу, что и любая переменная. Если вы хотите разделить переменную между модулями, вы помещаете ее в заголовок. То же самое относится к #defines.
Однако, странно использовать #ifdef, поскольку вы всегда будете иметь main.c. Вы не хотите менять код при каждом компиляции. Вместо этого используйте метод, описанный Адамом Залчманом