我有一个像这样的主文件:
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中使用define,如下所示:
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
我使用makefile构建它,如下所示:
生成文件:
all : a
./a
a : main_a.o shared.o
gcc -o $@ $^
%.o : %.c
gcc -c $<
然而这打印
i is: 0
现在我的问题是:为什么编译共享模块时定义似乎丢失了?我知道主模块是先编译的,所以定义应该在编译shared.c时解决。
我怀疑的是,预处理器可能会在每个模块构建开始时运行,而不仅仅是在项目开始时运行。如果这是正确的,有一种方法可以一次编译多个模块,以便在我上面尝试时使用预处理器吗?
答案 0 :(得分:12)
预编译器在编译之前为每个文件运行,即一次用于main_a.c,然后再次独立用于shared.c。编译shared.c时,MAIN_A未定义。
预处理器不能以您尝试的方式使用,即在编译单元之间记住状态。
您可以使用Makefile中的MAIN_A
编译器选项定义名称(例如-D
),并使用预处理器以与现在相同的方式测试此名称。这样定义发生在项目级别(在Makefile中)而不是在编译单元级别(在.c文件中)。
答案 1 :(得分: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
作为另一个文件。
答案 2 :(得分:0)
是的,你是对的,它们是完全独立的编译单元。
MAIN_A仅在main_a.c中定义
我想到的一个想法是将文件合在一起制作一个编译单元?
答案 3 :(得分:0)
全球定义A
gcc main_a.c shared.c -DA
答案 4 :(得分:-1)
定义几乎与任何变量相同的工作。如果要跨模块共享变量,请将其放在标题中。 #defines也一样。
然而,使用#ifdef很奇怪,因为你总是会有main.c.您不希望每次编译时都更改代码。相反,使用Adam Zalcman描述的方法