经过相当多的调试时间后,我觉得在我的代码中发现一个可以归结为这样的东西的傻了很傻:
int main()
{
double p1[] = { 1, 2, 3 };
double p2[] = { 1, 2, 3 };
int color = 1;
bool some_condition = true;
if (some_condition) (p1, p2, color);
}
(p1, p2, color)
表达式求值为最后一个操作符,但编译器是否应该以某种方式保护我? (Visual Studio什么都没说)
是的,你猜对了,我想调用一个绘制函数:Draw(p1, p2, color)
答案 0 :(得分:3)
在C ++中,表达式(p1, p2, color)
强制编译器将括号内的逗号解释为顺序评估运算符。
顺序求值运算符是一个二元运算符,它将第一个操作数计算为void
并丢弃结果,然后计算第二个操作数并返回其值和类型。因此,表达式(p1, p2, color)
将按以下方式进行评估:
p1
,然后评估(p2, color)
并返回结果(p2, color)
。p2
,然后评估color
并返回结果color
。因此声明:
if (some_condition) (p1, p2, color);
相当于:
if (some_condition) color;
某些编制者可能会发出警告,因为在评估表达式(p1, p2, color)
期间,p1
和p2
的评估将导致未使用:
CLANG LIVE DEMO GCC LIVE DEMO (正如您已经提到的那样 Visual Studio 根本不会引发任何警告。)
除了这些警告之外,代码是合法的C ++(即,C ++语法没有被违反)。
现在,编译器是否应该保护你是有争议的。在我的拙见中,它应该保护你,因为这样的表达虽然从C ++语法的角度来看可能是正确的,但很难发现错误(例如,在if
表达式内的分配的情况)。
答案 1 :(得分:3)
这是完全有效的代码,因此编译器不必发出诊断,尽管在这种情况下诊断会有所帮助。这是许多开发人员更喜欢clang
的原因之一,因为他们倾向于above what is required when it comes to diagnostic。
有关诊断消息的标准规则,我们可以转到draft C++ standard部分1.4
实施合规性(强调我的):
可诊断规则集包含所有语法和语义 本国际标准中的规则,但包含的规则除外 一个明确的符号“不需要诊断”或哪些是 被描述为导致“未定义的行为”。
- 醇>
虽然本国际标准仅规定了对C ++的要求 实现,如果这些要求通常更容易理解 它们被表达为对节目,节目部分或节目的要求 执行程序。这些要求具有以下含义:
如果本国际标准中的程序不包含违反规则的行为,则符合规定 应在其资源限制范围内接受并正确执行 2 该程序。
如果某个程序包含违反任何可诊断规则或某个构造中出现的构造 当实现不支持该构造时,此标准为“有条件支持”, 符合要求的实施应发出至少一条诊断信息。
如果某个程序违反了不需要诊断的规则,则本国际标准不对该程序的实施提出任何要求。
此程序不违反任何语法或语义规则,因此无需诊断。
我们有以下代码:
if (some_condition) (p1, p2, color);
^ ^ ^
1 2 3
1
是一个表达式语句,在此上下文中有效且 if语句。我们可以通过语法来看到这一点:
if ( condition ) statement
和
statement:
attribute-specifier-seqopt expression-statement
和
expression-statement:
expressionopt;
和
primary-expression:
( expression )
2
和3
都是逗号运算符,它将评估左操作数并丢弃该值,然后再次评估右操作数,此处无效。
那么5.18
逗号运算符部分是什么:
用逗号分隔的一对表达式从左到右进行评估; 左表达式是废弃的值表达式(第5条)。 83
和废弃值表达式在5
部分中介绍:
在某些情况下,表达式仅出现其副作用。 这样的表达式称为丢弃值表达式。
因为左手表达式的结果值被丢弃,所以我们只关心副作用。在您的特定情况下,评估变量除了生成值之外没有其他影响因此警告,但如果您在其位置使用了函数,例如:
bool func()
{
//...
}
并将您的代码更改为:
if (some_condition) (func(), func(), func() );
clang
和gcc
都不会提供警告,因为大概func
会执行您关心的 side-effet 。