C++ switch 语句表达式求值保证
C++ switch statement expression evaluation guarantee
关于开关,标准规定如下。 "When the switch statement is executed, its condition is evaluated and compared with each case constant."
是否意味着条件表达式只计算一次,并且由每个编译器的标准保证?
比如switch语句头部使用函数时,有副作用。
int f() { ... }
switch (f())
{
case ...;
case ...;
}
第 6.4.4 节:
...The value of a condition that is an expression is the value of the
expression, contextually converted to bool for statements other than
switch;...The value of the condition will be referred to as simply “the condition” where the
usage is unambiguous
根据我的理解,上面的引用等同于以下伪代码:
switchCondition := evaluate(expression)
现在添加您的报价
...its condition is evaluated and compared with each case constant.
应翻译为:
foreach case in cases
if case.constant == switchCondition
goto case.block
是的,看起来是这样。
我觉得保证f
只调用一次
首先我们有
The condition shall be of integral type, enumeration type, or class type.
[6.4.2(1)](非整数部分不适用),
The value of a condition that is an expression is the value of the
expression
[6.4 (4)]。此外,
The value of the condition will be referred to as simply “the condition” where the
usage is unambiguous.
[6.4 (4)] 这意味着在我们的例子中,"condition" 只是类型 int
的普通值,而不是 f
。 f
仅用于查找条件值。现在当控制到达 switch
语句时
its condition is evaluated
[6.4.2 (5)],即我们使用f
返回的int
的值作为我们的"condition"。然后最后的条件(它是 int
类型的值,而不是 f
)是
compared with each case constant
[6.4.2 (5)]。这不会再次触发 f
的副作用。
所有引用自 N3797。 (也查了N4140,没区别)
表达式保证只被控制流计算一次。这在标准 N4431 §6.4.2/6 中是合理的 开关语句 [stmt.switch](强调我的):
case and default labels in themselves do not alter the flow of
control, which continues unimpeded across such labels. To exit from a
switch, see break, 6.6.1. [ Note: Usually, the substatement that is
the subject of a switch is compound and case and default labels appear
on the top-level statements contained within the (compound)
substatement, but this is not required. Declarations can appear in the
substatement of a switch-statement. — end note ]
是的,表达式仅在执行 switch 语句时计算一次:
§ 6.4 选择语句
4 [...] The value of a condition that is an expression is the value of the
expression [...] The value of the condition will be referred to as simply “the condition” where the usage is unambiguous.
这意味着对表达式进行求值,其值被认为是 condition
,要针对每个 case
语句进行求值。
此代码打印 hello
一次还是两次?
int main() {
printf("hello\n");
}
嗯,我认为答案在于对标准描述内容的更一般理解,而不是具体的 switch
声明措辞。
根据程序执行[intro.execution]标准描述了一些抽象机器的行为执行根据C++语法解析的程序。它并没有真正定义 'abstract machine' 或 'executes' 的含义,但它们被假定为表示其明显的计算机科学概念,即计算机遍历抽象语法树并根据标准描述的语义。这意味着如果你写了一次东西,那么当 执行 到达那个点时,它只被评估一次。
更相关的问题是"when the implementation may evaluate something not the way written in the program"?为此,存在假设规则和一堆未定义的行为,这些行为允许实现偏离这种抽象解释。
阅读N4296
第 10 页第 14 段:
Every value computation and side effect associated with a full-expression is sequenced before every value
computation and side effect associated with the next full-expression to be evaluated.
当我读到段落的第一行时。 10(以上):
A full-expression is an expression that is not a sub-expression of
another expression.
我不得不相信 switch
语句的条件是一个完整表达式,并且每个条件表达式都是一个完整表达式(尽管在执行时微不足道)。
A switch
是语句而不是表达式(参见 6.4.2 和许多其他地方)。
因此,通过读取 switch
的评估必须在 case
常量的评估之前进行。
正如以往许多观点归结为曲折阅读规范得出一个明显的结论。
如果我对那句话进行同行评审,我会提出以下修正案(在粗体中):
When the switch statement is executed, its condition is evaluated
once per execution of the switch statement and compared with each case constant.
此问题已针对 C++ '20 进行了澄清,明确了条件被评估一次:
When the switch statement is executed, its condition is evaluated. If one of the case constants has the same value as the condition, control is passed to the statement following the matched case label.
change 的提交消息承认它之前可能令人困惑:
[stmt.switch] Clarify comparison for case labels
关于开关,标准规定如下。 "When the switch statement is executed, its condition is evaluated and compared with each case constant."
是否意味着条件表达式只计算一次,并且由每个编译器的标准保证?
比如switch语句头部使用函数时,有副作用。
int f() { ... }
switch (f())
{
case ...;
case ...;
}
第 6.4.4 节:
...The value of a condition that is an expression is the value of the expression, contextually converted to bool for statements other than switch;...The value of the condition will be referred to as simply “the condition” where the usage is unambiguous
根据我的理解,上面的引用等同于以下伪代码:
switchCondition := evaluate(expression)
现在添加您的报价
...its condition is evaluated and compared with each case constant.
应翻译为:
foreach case in cases
if case.constant == switchCondition
goto case.block
是的,看起来是这样。
我觉得保证f
只调用一次
首先我们有
The condition shall be of integral type, enumeration type, or class type.
[6.4.2(1)](非整数部分不适用),
The value of a condition that is an expression is the value of the expression
[6.4 (4)]。此外,
The value of the condition will be referred to as simply “the condition” where the usage is unambiguous.
[6.4 (4)] 这意味着在我们的例子中,"condition" 只是类型 int
的普通值,而不是 f
。 f
仅用于查找条件值。现在当控制到达 switch
语句时
its condition is evaluated
[6.4.2 (5)],即我们使用f
返回的int
的值作为我们的"condition"。然后最后的条件(它是 int
类型的值,而不是 f
)是
compared with each case constant
[6.4.2 (5)]。这不会再次触发 f
的副作用。
所有引用自 N3797。 (也查了N4140,没区别)
表达式保证只被控制流计算一次。这在标准 N4431 §6.4.2/6 中是合理的 开关语句 [stmt.switch](强调我的):
case and default labels in themselves do not alter the flow of control, which continues unimpeded across such labels. To exit from a switch, see break, 6.6.1. [ Note: Usually, the substatement that is the subject of a switch is compound and case and default labels appear on the top-level statements contained within the (compound) substatement, but this is not required. Declarations can appear in the substatement of a switch-statement. — end note ]
是的,表达式仅在执行 switch 语句时计算一次:
§ 6.4 选择语句
4 [...] The value of a condition that is an expression is the value of the expression [...] The value of the condition will be referred to as simply “the condition” where the usage is unambiguous.
这意味着对表达式进行求值,其值被认为是 condition
,要针对每个 case
语句进行求值。
此代码打印 hello
一次还是两次?
int main() {
printf("hello\n");
}
嗯,我认为答案在于对标准描述内容的更一般理解,而不是具体的 switch
声明措辞。
根据程序执行[intro.execution]标准描述了一些抽象机器的行为执行根据C++语法解析的程序。它并没有真正定义 'abstract machine' 或 'executes' 的含义,但它们被假定为表示其明显的计算机科学概念,即计算机遍历抽象语法树并根据标准描述的语义。这意味着如果你写了一次东西,那么当 执行 到达那个点时,它只被评估一次。
更相关的问题是"when the implementation may evaluate something not the way written in the program"?为此,存在假设规则和一堆未定义的行为,这些行为允许实现偏离这种抽象解释。
阅读N4296
第 10 页第 14 段:
Every value computation and side effect associated with a full-expression is sequenced before every value computation and side effect associated with the next full-expression to be evaluated.
当我读到段落的第一行时。 10(以上):
A full-expression is an expression that is not a sub-expression of another expression.
我不得不相信 switch
语句的条件是一个完整表达式,并且每个条件表达式都是一个完整表达式(尽管在执行时微不足道)。
A switch
是语句而不是表达式(参见 6.4.2 和许多其他地方)。
因此,通过读取 switch
的评估必须在 case
常量的评估之前进行。
正如以往许多观点归结为曲折阅读规范得出一个明显的结论。
如果我对那句话进行同行评审,我会提出以下修正案(在粗体中):
When the switch statement is executed, its condition is evaluated once per execution of the switch statement and compared with each case constant.
此问题已针对 C++ '20 进行了澄清,明确了条件被评估一次:
When the switch statement is executed, its condition is evaluated. If one of the case constants has the same value as the condition, control is passed to the statement following the matched case label.
change 的提交消息承认它之前可能令人困惑:
[stmt.switch] Clarify comparison for case labels