【问题标题】:Can i write preprocessor directives anywhere in my c program?我可以在我的 c 程序的任何地方编写预处理器指令吗?
【发布时间】:2017-08-29 20:41:17
【问题描述】:

是否必须在程序顶部和main函数之外编写#include?

我尝试在 main 函数中使用 #define 预处理器,它工作正常,只有一个异常..我使用 define 指令定义的常量只能在 #define 行之后使用 例如说printf("%d",PI); #define PI 3.14将给出错误“未定义的符号PI”。但是在下面的代码中我没有遇到任何错误

#define PI 3.14 
printf("%d",PI);

这是因为 C 是一种过程语言并且过程语言实现了自上而下的方法吗?

我也想知道我们是否也可以在主函数或其他预处理器指令中只使用#define?如果我们可以使用那么哪些? 或者是相反的方式,而不是#include,我们可以在主函数中使用所有预处理器指令?

【问题讨论】:

  • "以下代码我没有遇到任何错误" --> 代码正在尝试使用"%d" 打印double --> UB。启用所有编译警告。
  • 请注意,C 标准(我相信 POSIX 标准)要求它们定义的标头必须包含在文件范围内,而不是在外部声明范围内(函数,或在变量声明)。你可以在任何你喜欢的地方使用#include 和你自己的标题;您有责任使其正常工作。如果您的标头包含系统标头,那么您毕竟必须遵守文件范围规则。请注意,尽管包含通常位于文件的顶部,但这不是必需的。
  • 如果您将代码修复为 #define PI 3.14 printf("%f",PI); ,问题仍然是为什么顺序很重要。然后是程序问题。

标签: c c-preprocessor


【解决方案1】:

唯一不能放置预处理器指令的地方是宏扩展。唯一的例外是#pragma,也可以写成_Pragma()

这与“程序”无关,但由于 C 是根据 8 个翻译阶段定义的,每个翻译阶段在下一阶段之前“好像”完全完成。有关详细信息,请参阅 C11 标准,第 5.1.1.2 节。


在文件开始后使用预处理器指令有用的一个例子是"X Macro" technique(许多人只知道“那些.def文件”)。

【讨论】:

    【解决方案2】:

    预处理器指令几乎可以在任何地方使用。当然,如果你滥用它,你很容易让你的代码混乱。

    【讨论】:

    • 不幸的是,#include 并非无处不在。为什么会这样?我举了一个简单的例子。说 int main(void) { #include } 我在 turbo c 编译器中遇到了 6 个错误,主要是未定义的符号
    • #include 确实适用于任何地方......但它所做的是将包含文件的内容复制并粘贴到您放置 #include 指令的位置。所以如果你把它放在main 中,它会尽职地把math.h 的内容放在你的main 函数中,这可能不会编译。但是,如果您有一个包含可在 main 函数中编译的代码的文件,而您 #included 则可以正常工作(我不建议您实际这样做)。
    • @CharlesSrstka,#include 在很多地方都有效;它是被写入包含在全局范围中的标头。有#define some_macro some value和#include "special.c"的软件;有时数组中充满了包含的文件。
    【解决方案3】:

    预处理器在编译器将源代码转换为目标代码之前完成其工作。预处理主要是字符串替换任务,因此它可以放置在代码中的任何位置。当然,如果生成的扩展在语法上不正确,扩展的源代码将无法编译。

    通常可以容忍的做法是在函数中嵌入条件编译指令,以允许函数使用特定于平台的 API。

    void some_wrapper_function () {
    #if defined(UNIX)
        some_unix_specific_function();
    #elif defined(WIN32)
        some_win32_specific_function();
    #else
        #error "Compiled on an unsupported platform"
    #endif
    }
    

    就其性质而言,指令本身通常必须在行首定义,而不是在源代码行中间的某个位置。但是,定义的宏当然可以出现在源代码中的任何位置,并且将根据您的指令定义的替换规则进行替换。

    【讨论】:

    • _Pragma 是预处理器运算符,而不是指令,其行为类似于 #pragma,除了运算符版本可以在任何可能使用宏的地方使用。
    【解决方案4】:

    这里的诀窍是要意识到 # 指令传统上由预处理器解释,该预处理器在任何编译之前运行。预处理器将生成一个新的源文件,然后对其进行编译。我不认为任何现代编译器默认都是这样工作的,但同样的原则也适用。

    所以当你说

    #include "foo.h"
    

    你是说“将 foo.h 的全部内容插入到我的源代码中,从这一行开始。”

    您几乎可以在源文件中的任何位置使用此指令,但在源文件开头以外的任何位置使用它很少有用(而且不经常可读)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-11
      • 1970-01-01
      • 1970-01-01
      • 2011-05-02
      • 2011-10-04
      相关资源
      最近更新 更多