为什么一个函数中的预处理程序指令会影响另一个函数的编译?

时间:2017-07-22 15:19:14

标签: c io c-preprocessor

以下程序成功编译并打印 1000 ,甚至没有从foo()函数调用main()函数。怎么可能?

#include<stdio.h>


void foo()
{
    #define ans 1000
}

int main() {

  printf("%d", ans);
  return 0;
}

3 个答案:

答案 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,并尝试在代码中查找使用这些定义的位置。如果您没有使用过它们,它将继续运行(无关紧要);如果已经使用过,它将用实际定义的值替换标签。