以下程序成功编译并打印 1000 ,甚至没有从foo()
函数调用main()
函数。怎么可能?
#include<stdio.h>
void foo()
{
#define ans 1000
}
int main() {
printf("%d", ans);
return 0;
}
答案 0 :(得分:10)
#define
由在编译器之前暂存的预处理器运行。预处理器完成后,代码将如下所示:
/* Everything that is inside stdio.h is inserted here */
void foo()
{
}
int main() {
printf("%d", 1000);
return 0;
}
这就是实际编译的内容。
预处理器对于使头文件有效非常重要。在其中,您会看到以下结构:
#ifndef foo
#define foo
/* The content of the header file */
#endif
如果没有这个,如果头文件包含多次,编译器会抱怨。您可能会问为什么要多次包含头文件。好吧,头文件可以包含其他头文件。考虑这个宏,这对调试很有用。它打印变量的名称,然后输出值。请注意,您必须为不同类型执行单独的版本。
#define dbg_print_int(x) fprintf(stderr, "%s = %d", #x, x)
这是非常通用的,因此您可能希望将其包含在头文件中供自己使用。由于它需要stdio.h,我们将其包括在内。
/* debug.h */
#include <stdio.h>
#define dbg_print_int(x) fprintf(stderr, "%s = %d", #x, x)
当您包含此文件并在主程序中包含stdio.h时会发生什么?那么,stdio.h将被包含两次。这就是为什么debug.h应该是这样的:
/* debug.h */
#ifndef DEBUG_H
#define DEBUG_H
#include <stdio.h>
#define dbg_print_int(x) fprintf(stderr, "%s = %d", #x, x)
#endif
文件stdio.h具有相同的构造。这里的主要内容是在编译器之前运行。 define是一个简单的替换命令。它对范围或类型一无所知。但是,正如您在此处所看到的,内置了一些基本逻辑。预处理器所做的另一件事是删除所有注释。
您可以在此处详细了解C预处理器:http://www.tutorialspoint.com/cprogramming/c_preprocessors.htm
答案 1 :(得分:3)
#define在编译器执行任何操作之前由预处理器处理。这是一个简单的文本替换。预处理器甚至不知道代码行是在函数,类或其他内部还是外部[参考:https://stackoverflow.com/a/36968600/5505997]。显然,您不需要调用函数来设置值,显然在编译期间不会出现任何错误。
答案 2 :(得分:1)
正如其他人所述,#define是预处理程序指令,而不是C源代码。参见维基here。
要点是,在代码中 #define ans 1000 不是变量定义,这意味着即使您在主程序中调用foo(),您仍不会在运行时设置“ ans”,因为它根本不是变量。它只是告诉预处理器在源代码中找到“ label”“ ans”时该如何处理。
在此示例中,main()本质上将调用一个空的foo()函数:
int main()
{
foo(); // Calls an empty function
printf("%d", ans); // ans will have been substituted by 1000 by the time you start executing you code
return 0;
}
在开始执行main()时,“ ans”的定义将不再存在。这就是预处理器的部分工作。它查找整个源代码中声明的所有#define,并尝试在代码中查找使用这些定义的位置。如果您没有使用过它们,它将继续运行(无关紧要);如果已经使用过,它将用实际定义的值替换标签。