【问题标题】:Pre-processor parsing on C++C++中的预处理器解析
【发布时间】:2017-01-28 15:03:57
【问题描述】:

如果我们想使用用户输入在程序中做某事,或者打印我们需要的结果

 #include <iostream>

否则,coutcin 将不会被编译器确认。但是命令#include 是预处理器命令。当我编写程序时,发生了以下情况。我写了以下代码:

#define PRINT_DEBUG_INFO(a) {cout << “Info: ” << a << endl;}
#include <iostream>

并且没有弹出错误。在包含iostream 之前如何使用cout?即使我声明 PRINT_DEBUG_INFO(a) 而不包括 iostream,我也不会收到编译错误。
谁能解释一下为什么会这样?

【问题讨论】:

  • define 不是函数,它只会复制所有代码并替换您使用的任何位置。
  • #include &lt;iostream&gt;,不是#include iostream
  • 在声明之前您没有“使用”cout。您所做的只是定义一个宏,其中包含文本cout(和endl),稍后可以在代码中使用。
  • 想象一下我写了void func() {int cout, endl; PRINT_DEBUG_INFO("blah");},那么cout 丢失就没有问题了(尽管尝试在数字和字符串上使用&lt;&lt; 还有另一个问题)。
  • 预处理器只是一只猴子,它在编译器看到它之前对你的代码进行 Ctrl-C 和 Ctrl-V,它对编译器错误一无所知。 :)

标签: c++ c-preprocessor


【解决方案1】:

预处理器不需要评估任何 C++ 声明的符号来完成其工作。

纯文本处理,所以定义一个像

这样的宏
#define PRINT_DEBUG_INFO(a) {cout << “Info: ” << a << endl;}

并像这样扩展它

#include <iostream>

void foo {
  int a = 5;
  PRINT_DEBUG_INFO(a);
}

会变成

// All the literal stuff appearing in <iostream>

void foo {
  int a = 5;
  {cout << “Info: ” << a << endl;};
}

因此,在宏的定义或扩展期间,没有任何关于正确 C++ 语法的检查。

这些语句将由 C++ 编译器进一步处理,它会抱怨 cout 未在全局范围内声明。

要解决此问题,请像

一样声明您的宏
#define PRINT_DEBUG_INFO(a) {std::cout << “Info: ” << a << std::endl;}

【讨论】:

  • 对不起,我完全忘记了。再次感谢
  • 语法 is 检查'during 扩展',但不是在定义期间,也不是beforeuntil 扩展。并且要明确:lexing(它在形式上与语法分离,尽管许多人将它们放在一起考虑)在定义期间完成/检查。
  • 不错的答案。只需补充一点,您始终可以尝试仅单独运行预处理器(使用 GCC 的 -E 开关)并查看将/将被输入编译器的代码。在调试更复杂的宏时,这是一种非常有用的技术。
  • @dave_thompson_085:我可能是错的,但我的理解是预处理器的词法分析在技术上与编译器的词法分析是分开的。毕竟,它们通常被实现为字面上独立的程序。
  • @ruakh:传统上它们是分开的,尽管我认为这已经变得不那么流行了,但如果是这样,标记必须保持不变,尽管只有编译器将它们解释为关键字、类型、变量等;在 C++ 标准的任何版本(或更便宜的草案)中查看 2[lex] 中的阶段。这是由第一个 C 标准标准化的;在此之前,您可以例如#define f(a,b) a/**/b 并使用 f(AB,CD)some 实现中获取单个令牌 ABCD,但在 C89 之后它必须是两个令牌 AB CD 并且要获得“粘贴”,您必须明确使用 @ 987654331@.
【解决方案2】:

你定义了 PRINT_DEBUG_INFO 但你没有使用它,所以编译器没有什么可以编译或抱怨的。

【讨论】:

    【解决方案3】:

    您只是在定义 PRINT_DEBUG_INFO(a) 而没有使用它。当你在你的程序中实际使用它时,你会得到cout没有定义的错误。

    当您不实际使用它时,编译器找不到替换已定义常量的地方。当您实际使用它时,程序会在编译期间展开并显示错误。

    此外,您的宏中有一个括号,它会用括号展开,可能会导致错误。

    【讨论】:

    • 你能解释一下你的句子/段落'一个括号......用括号扩展并可能导致错误'吗?我认为“用括号扩展”位让我担心,但我不确定您要建议什么。 {…} 宏的最大问题是你不能写 if (something) PRINT_DEBUG_INFO(something); else { …do something… } 因为分号意味着 else 无效。通常的解决方法是#define PRINT_DEBUG_INFO(a) do { … } while (0),它会让一切再次干净。
    猜你喜欢
    • 1970-01-01
    • 2010-09-22
    • 2011-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-29
    • 2019-11-29
    相关资源
    最近更新 更多