2012-01-02 3 views
12

У меня есть основной файл, как так:#define сферы в нескольких файлах

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; 
} 

Я хочу использовать определение в shared.h так:

совместно .h

#if defined(MAIN_A) 
# define A 
#endif 

Так что я могу объявить переменную в зависимости от того, присутствует или нет основной файл, как это:

shared.c

#include "shared.h" 

#if defined(A) 
int i = 1; 
#else 
int i = 0; 
#endif 

Я построить его с помощью Makefile, который выглядит следующим образом:

Makefile:

all : a 
    ./a 

a : main_a.o shared.o 
    gcc -o [email protected] $^ 

%.o : %.c 
    gcc -c $< 

Однако это печатает

i is: 0 

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

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

+0

Какой '# define' MAIN_A или A? –

+3

+1 за то, что вы собрались вместе, прежде чем публиковать ... –

+0

Это лучший ответ: http://stackoverflow.com/a/2649569/243712 – poolie

ответ

10

Препроцессор запускается для каждого файла перед его компиляцией, то есть один раз для main_a.c, а затем снова самостоятельно для shared.c. Когда shared.c скомпилирован, MAIN_A не определено.

Препроцессор не может использоваться так, как вы пытаетесь, т. Е. Запоминать состояние в единицах компиляции.

Что вы можете сделать, это определить имя (например, MAIN_A) с использованием опции компилятора -D в вашем файле Makefile и протестировать это имя, используя препроцессор так же, как вы это делаете сейчас. Таким образом, определение выполняется на уровне проекта (в Makefile), а не на уровне единицы компиляции (в .c файле).

+0

Опция -D работает красиво. Спасибо. – Kenneth

1

Позвольте мне сделать здесь препроцессор и развернуть все ваши макросы. В main.c, MAIN_A определено, поэтому определено A. Ничто не зависит от A в main.c, а i - внешний.

В shared.c, MAIN_A и тот самый A не определены, и i 0.

Короче говоря, препроцессор не может транспортировать информацию между единицами компиляции. Это хорошая практика, потому что в противном случае программы быстро станут нечитаемыми, и вам придется перекомпилировать все единицы компиляции, когда одна единица изменится (поскольку символы могли быть изменены). Решить проблему, установив i явно main:

int main() { 
    i = 1; 
} 

Это более многословным, но также намного понятнее читателю. Если вы хотите инкапсулировать, определите функцию InitializeShared. Если вы действительно хотите скомпилировать некоторый код как единый блок компиляции, сделайте один из файлов заголовочным файлом, а #include - другим.

0

Да, вы правы, это совершенно отдельные единицы компиляции.

MAIN_A определяется только в main_a.c

Одна мысль, которая приходит на ум, чтобы кошке файлы вместе, чтобы сделать одну единицу компиляции?

-1

Определяет почти работать так же, как и любой переменной. Если вы хотите разделить переменную между модулями, вы помещаете ее в заголовок. То же самое касается #defines.

Тем не менее, странно использовать #ifdef, поскольку вы всегда будете иметь main.c. Вы не хотите менять код при каждом компиляции. Вместо этого используйте метод, описанный Adam Zalcman

+0

Если вы имеете в виду разделяемые переменные declerations в заголовках, то, возможно. Я бы предпочел не делать этого, но это скорее предпочтение стиля. Я никогда не буду добавлять определения переменных в файлы заголовков. Но мой вопрос заключался в том, можно ли макросу в другом модуле увидеть #define в другом модуле, и ответ явно не был. – Kenneth