【问题标题】:Why does the preprocessor directive in one function affect the compilation of another?为什么一个函数中的预处理器指令会影响另一个函数的编译?
【发布时间】:2017-07-22 15:19:14
【问题描述】:

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

#include<stdio.h>


void foo()
{
    #define ans 1000
}

int main() {

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

【问题讨论】:

  • 预处理器不知道作用域是什么。
  • 大致有两种语言:预处理器的语言和核心C。它们几乎是独立的,第一种被翻译的是预处理器的语言,其结果输入到core-C编译器。 .
  • @Gear 你应该发表你的评论作为答案。

标签: c io c-preprocessor


【解决方案1】:

#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 具有相同的结构。这里的主要内容是它在编译器之前运行。定义是一个简单的替换命令。它对范围或类型一无所知。但是,正如您在此处看到的,其中内置了一些基本逻辑。预处理器做的另一件事是删除所有的 cmets。

您可以在此处阅读有关 C 预处理器的更多信息:http://www.tutorialspoint.com/cprogramming/c_preprocessors.htm

【讨论】:

    【解决方案2】:

    #define 在编译器执行任何操作之前由预处理器处理。这是一个简单的文本替换。预处理器甚至不知道代码行是在函数、类还是其他任何东西的内部或外部 [参考:https://stackoverflow.com/a/36968600/5505997].显然您不需要调用该函数来设置值,并且显然您在编译过程中不会出现任何错误。

    【讨论】:

      【解决方案3】:

      正如其他人所说,#define 是一个预处理器指令,而不是 C 源代码。请参阅 Wiki here
      重点是,在您的代码中 #define ans 1000 不是变量定义,这意味着即使您在 main 中调用 foo(),您仍然不会在运行时设置“ans”,因为它根本不是一个变量。它只是告诉预处理器如何处理“标签”“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”的定义将不再存在。这就是预处理器所做的(部分)。它会查找在您的整个源代码中声明的所有#defines,并尝试在您的代码中找到您使用这些定义的位置。如果您没有使用它们,它会继续(不在乎),如果有,它会用实际定义的值替换标签。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-02
        • 1970-01-01
        • 1970-01-01
        • 2022-01-09
        相关资源
        最近更新 更多