【问题标题】:Simple c++ program gets compilation errors简单的 c++ 程序出现编译错误
【发布时间】:2015-05-24 16:38:39
【问题描述】:

当我试图编译这段代码时,它显示错误:

main.cpp:19:3: error: invalid operands of types 'void' and 'int' to binary 'operator!='

这是文件:

#include <iostream>
#include <cstdio>
using namespace std;
#define $ DEBUG
#define DEBUG 1
#define _(out) do{  std::cout << __FILE__ << ":" << __LINE__ \
                       << " " << out << '\n';}while(0)
#define _(out) printf(out);
int main(){

#ifdef LOCAL_PROJECT
    #define DEBUG 0
#endif

    $ && ({
        _("eeeeewe");
    });//line 19

    return 0;
}

$ 是DEBUG 的简单名称,在运行时它是0 或1。

编译错误是针对这个源文件的。 如何摆脱这个并编译?

【问题讨论】:

  • @UmNyobe “简单” c++ 程序。 (你不能争论它是 C++)
  • @UmNyobe 我做错了什么?
  • 一切。不要使用宏。
  • @Puppy 好的,我可以做到debug &amp;&amp; printf('1');,debug 是布尔值。但是当我需要更多表达时,不仅仅是printf,该怎么办?
  • 这不是你真正的程序,是吗?错误信息和代码不匹配。

标签: c++ logging macros gcc-extensions


【解决方案1】:

您在这里做的有些事情是不可取的,有些是非法的。但我给了你一个赞成票,至少提醒我注意gcc extension I hadn't seen:

#include <iostream>

int main() {
    int x = ({std::cout << "I'm surprised this prints "; 10 + 20;});
    std::cout << x << "\n";
}

这确实在 IDEone I'm surprised this prints 30 上输出,即使在 C++14 设置下也是如此。在coliru,虽然你得到:

main.cpp:4:17:警告:ISO C++ 禁止在表达式 [-Wpedantic] 中使用大括号组

然而,既然我们已经共同学习,请避免使用非标准扩展。部分原因是 StackOverflow 上的人会对你大喊大叫。但主要是因为当你坚持已经被大量思考问题的人同意和审查的子集时,生活已经足够艰难,试图在语言发展、教育和使用方面找到真正的土地。

(“一个人当时为那个项目添加的语言功能”可能是一个坏主意——对于“那个人”或“那个项目”的任何定义。) p>

此外,类似这样的东西——很少使用——可能在优化器中缺乏对表达该表达式的关注。这意味着充其量它比其他方式慢,最坏的情况是它有随机错误。


继续:

  • 在标识符名称is apparently "implementation-defined behavior" 中使用$。这意味着规范中没有任何内容不允许它......但也没有说编译器也必须实现它。它可能不是您想要发明新的创造性用途的东西,并且只有在您遇到与 VAX 上的旧代码或其他东西桥接的情况时才使用。

  • 另一方面,您只需 you can't name any global variables or macros starting with an underscore。它们保留给编译器实现以供自己使用。 (如果您阅读所有内容,您会看到其他不寻常的细微差别,例如在任何范围内不能有以下划线开头并后跟大写字母的标识符,尽管如果字母是小写的,您可以定义它们本地。通常人们将它用于成员变量,但必须小心遵守规则。)

  • 出于兼容性目的,可以使用printf...因为显式设计允许使用旧的 C 程序并慢慢将它们升级到 C++。但是您不应该使用它编写新的结构或代码,如果您想了解一些基本原理,请阅读简短的论文Learning Standard C++ as a New Language。它本身就是一篇旧论文,但它来自 Bjarne Stroustrup,并且很好地解决了这一点。

然而,为什么这种方法通常是错误的,“最大”的问题是,有比尝试将文本代码段抓取到宏中更可靠的方法来做到这一点。许多主题需要研究,例如 C++11 中 lambdas 的使用。但更一般地说,您应该关注您在这里的愿望,即日志记录的主题领域。快速搜索标签交叉点可以为您提供很好的建议:

Search Query for [c++] [logging] __FILE__

如何摆脱它并编译?

在流程中引入中间步骤。

  1. 摆脱这个...(代码!)
  2. 阅读我提供的链接。
  3. 查看用于实现此目标的方法并评估您喜欢或不喜欢它们的哪些方面。
  4. 编写使用更好做法的新代码,或借鉴他人的经验。
  5. ...并编译。 :-)

【讨论】:

  • 感谢您的解释。我真的不明白为什么要投反对票.. 目标是优化代码 if (a) { call_a_func(); call_second_func(42); } 到 a &amp;&amp; { call_a_func(); call_second_func(42); } 怎么做?..
  • @Daniel 通过“优化”,您的意思似乎是“减少打字”。 (希望您不要将较短的 C++ 代码与必然更快的代码混淆。)但是您不要将 C++ 的语法弯曲成您想要的编写方式,它会弯曲您。 :-) 试图希望 C++ 的语法不是一棵好树来吠叫,并且这样做你会错过语言的真正优势和力量(并打破有预处理器错误的东西)。但是...如果您正在寻求对语法进行任意重新布线以创建自己的语言,我可能建议您查看Rebol and Red。
  • 好的。现在我明白了,写更少的代码根本不是一种优化。)
  • @Daniel 除非您非常了解汇编和低级实现,否则编译器可能会做更多您可以自己做的优化。使用 -O4 或其他标志会有所帮助。
【解决方案2】:

在调用宏后删除分号,或者只是更改宏以删除 printf(out) 后的分号。

宏在引起此类错误时尤其不方便。因为宏像查找+复制+粘贴一样被直接替换,所以有时会导致没有意义的结果。

#include <iostream>
#include <cstdio>
using namespace std;
#define $ DEBUG
#define DEBUG 1
#define _(out) do{  std::cout << __FILE__ << ":" << __LINE__ \
                       << " " << out << '\n';}while(0)
#define _(out) printf(out);
int main(){

#ifdef LOCAL_PROJECT
    #define DEBUG 0
#endif

    $ && ({
        _("eeeeewe")
    });//line 19

    return 0;
}

【讨论】:

  • 另外,我建议你永远不要在 C++ 中使用宏。有更好的替代方案,即 inline 和 const,因此您不应该将宏用于除标头保护之外的任何东西,以确保您不会两次包含相同的标头。
  • 你的回答让我看着这个然后去“等等,什么,可以编译?”这让我调查了原因,并发布了my long answer。如果你后来继续看其他东西,你可能想看,因为它明确提到了除宏之外的其他几个问题。
猜你喜欢
  • 2022-07-13
  • 1970-01-01
  • 2017-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多