c++ - 逗号分隔的语句是否被视为完整语句? (和其他诊断问题)

标签 c++ gcc clang compiler-warnings

我猜答案是“否”,但从编译器的角度来看,我不明白为什么。

我编写了一个非常简单的代码,它严重影响了编译器诊断(clang 和 gcc),但我想在报告错误诊断之前确认该代码没有格式错误。我应该指出,这些不是编译器错误,输出在所有情况下都是正确的,但我对警告表示怀疑。

考虑以下代码:

#include <iostream>

int main(){
  int b,a;
  b = 3;
  b == 3 ? a = 1 : b = 2;
  b == 2 ? a = 2 : b = 1;
  a = a;
  std::cerr << a << std::endl;
}

a的赋值是重言式,意思是a会在两个三元语句之后初始化,与b无关。 GCC 对此代码非常满意。 Clang 稍微聪明一些,并且发现了一些愚蠢的东西(警告:显式地将类型为 'int' 的变量分配给自身 [-Wself-assign]),但没什么大不了的。

现在是一样的东西(至少在语义上),但语法更短:

#include <iostream>

int main(){
  int b,a = (b=3, 
             b == 3 ? a = 1 : b = 2, 
             b == 2 ? a = 2 : b = 1, 
             a);
  std::cerr << a << std::endl;
}

现在编译器给了我完全不同的警告。 Clang 不再报告任何奇怪的东西(由于括号优先级,这可能是正确的)。 gcc有点吓人,说:

test.cpp: In function ‘int main()’:
test.cpp:7:15: warning: operation on ‘a’ may be undefined [-Wsequence-point]

但这是真的吗?那个序列点警告给了我一个提示,即逗号分隔的语句在实践中的处理方式不同,但我不知道它们是否应该这样做。

它变得更奇怪了,将代码更改为:

#include <iostream>

int main(){
  int b,a = (b=3, 
             b == 3 ? a = 1 : b = 2, 
             b == 2 ? a = 2 : b = 1, 
             a+0); // <- i just changed this line
  std::cerr << a << std::endl;
}

然后突然clang意识到a可能有问题:

test.cpp:7:14: warning: variable 'a' is uninitialized when used within its own initialization [-Wuninitialized]
             a+0);
             ^

但是之前 a 没有问题...由于某些原因,clang 在这种情况下无法发现重言式。同样,这可能只是因为这些不再是完整的陈述。

问题是:

  • 此代码是否有效且定义明确(在所有版本中)?
  • 如何处理逗号分隔的语句列表?它应该与带有显式语句的代码的第一个版本不同吗?
  • GCC 是否有权报告未定义的行为和序列点问题? (在这种情况下,clang 缺少一些重要的诊断)我知道它说可能,但仍然......
  • 是否有权报告 a 在最后一种情况下可能未初始化? (那么它应该与前一个案例具有相同的诊断)

编辑和评论:

  • 我收到了几条(正确的)评论,认为这段代码一点也不简单。这是真的,但关键是编译器在遇到初始化程序中的逗号分隔语句时会误诊。这是一件坏事。我使我的代码更完整以避免 “你尝试过这种语法...” 评论。可以编写一个更现实、更易于阅读的问题版本,这会显示错误的诊断,但我认为这个版本显示了更多信息并且更完整。
  • 在编译器折磨测试套件中,这将被认为是非常易于理解和可读的,它们的表现要差得多:) 我们需要这样的代码来测试和评估编译器。这在生产代码中看起来不太好看,但这不是重点。

最佳答案

5 Expressions

10 In some contexts, an expression only appears for its side effects. Such an expression is called a discarded-value expression. The expression is evaluated and its value is discarded

5.18 Comma operator [expr.comma]

A pair of expressions separated by a comma is evaluated left-to-right; the left expression is a discarded-value expression (Clause 5).83 Every value computation and side effect associated with the left expression is sequenced before every value computation and side effect associated with the right expression. The type and value of the result are the type and value of the right operand; the result is of the same value category as its right operand, and is a bit-field if its right operand is a glvalue and a bit-field.

在我看来你的陈述没有任何问题。

仔细查看 g++ 警告,可能未定义,这告诉我解析器不够聪明,无法确保 a=1 是评估。

关于c++ - 逗号分隔的语句是否被视为完整语句? (和其他诊断问题),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16798422/

相关文章:

c++ - 有没有办法在 C++ 中预先声明嵌套类?

c++ - qtcreator 没有使用指定的编译器

c++ - 为什么 GCC 只是通过将其置于循环中而被欺骗以允许未定义的行为?

gcc - 无法交叉编译 curl-rust 示例

c++ - 我可以使用 CLang 和 libstdc++ (emmintrin.h)

c++ - 对于像 C++ 这样的现实世界语言,时间复杂度有一致的定义吗?

C++ 隐式和显式继承构造函数调用

c++ - 模板特化和DLL:Visual Studio与(GCC/Clang)

c++ - 如何在 OpenCV 2.4.13 中导入经过训练的 SVM 检测器

clang - 为什么 clang -dumpversion 报告 4.2.1