Подтвердить что ты не робот

#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

Теперь я задаюсь вопросом: почему возникает ошибка при компиляции совместно используемого модуля? Я знаю, что основной модуль скомпилирован первым, поэтому определение должно быть разрешено скомпилированным временем. Компиляция.

У меня есть подозрение, что препроцессор может запускаться в начале каждой сборки модуля, а не только в начале проекта. Если это правильно, есть способ скомпилировать более одного модуля за раз, чтобы использовать препроцессор, как я пытаюсь сделать выше?

4b9b3361

Ответ 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. Вы не хотите менять код при каждом компиляции. Вместо этого используйте метод, описанный Адамом Залчманом