C++ switch statement expression evaluation guarantee

C++StandardsLanguage Lawyer

C++ Problem Overview


Regarding switch the standard states the following. "When the switch statement is executed, its condition is evaluated and compared with each case constant."

Does it mean that the condition expression evaluated once and once only, and it is guaranteed by the standard for each compiler?

For example, when a function is used in the switch statement head, with a side effect.

int f() { ... }
switch (f())
{
    case ...;
    case ...;
}

C++ Solutions


Solution 1 - C++

I think it is guaranteed that f is only called once.

First we have

> The condition shall be of integral type, enumeration type, or class type.

[6.4.2 (1)] (the non-integral stuff does not apply here), and

> The value of a condition that is an expression is the value of the expression

[6.4 (4)]. Furthermore,

> The value of the condition will be referred to as simply “the condition” where the usage is unambiguous.

[6.4 (4)] That means in our case, the "condition" is just a plain value of type int, not f. f is only used to find the value for the condition. Now when control reaches the switch statement

> its condition is evaluated

[6.4.2 (5)], i.e. we use the value of the int that is returned by f as our "condition". Then finally the condition (which is a value of type int, not f), is

> compared with each case constant

[6.4.2 (5)]. This will not trigger side effects from f again.

All quotes from N3797. (Also checked N4140, no difference)

Solution 2 - C++

Reading N4296

Page 10 para 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.

When I read the first line of para. 10 (above that):

> A full-expression is an expression that is not a sub-expression of > another expression.

I have to believe that the condition of a switch statement is a full-expression and each condition expression is a full expression (albeit trivial at execution).

A switch is a statement not an expression (see 6.4.2 and many other places).

So by that reading the evaluation of the switch must take place before the evaluation of the case constants.

As ever many points boil down to tortuous reading of the specification to come to an obvious conclusion.

If I peer reviewed that sentence I would propose the following amendment (in bold):

> When the switch statement is executed, its condition is evaluated > once per execution of the switch statement and compared with each case constant.

Solution 3 - C++

Yes the expression is evaluated only once when the switch statement is executed:

§ 6.4 Selection statements > 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.

This means that the expression is evaluated and its value is considered the condition to be evaluated against each case statement.

Solution 4 - C++

Section 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

In my understanding, the quote above is equivalent to the following pseudo-code:

switchCondition := evaluate(expression)

Now add your quote

> ...its condition is evaluated and compared with each case constant.

Which should be translated to:

foreach case in cases
    if case.constant == switchCondition
         goto case.block

So yeah, it looks like this is the case.

Solution 5 - C++

Does this code print hello once or twice?

int main() {
    printf("hello\n");
}

Well, I think the answer is in the more general understanding of what the standard describes rather than in the specific switch statement wording.

As per Program execution [intro.execution] the standard describes the behaviour of some abstract machine that executes the program parsed according to the C++ grammar. It does not really define what 'abstract machine' or 'executes' mean, but they are assumed to mean their obvious computer science concepts, i.e. a computer that goes through the abstract syntax tree and evaluates every part of it according to the semantics described by the standard. This implies that if you wrote something once, then when the execution gets to that point, it is evaluated only once.

The more relevant question is "when the implementation may evaluate something not the way written in the program"? For this there is the as-if rule and a bunch of undefined behaviours which permit the implementation to deviate from this abstract interpretation.

Solution 6 - C++

This issue was clarified for C++ '20 making it clear that the condition is evaluated once:

> 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.

The commit message for the change acknowledges that it was potentially confusing before: > [stmt.switch] Clarify comparison for case labels

Solution 7 - C++

The expression is guaranteed that is evaluated only once by the flow of control. This is justified in the standard N4431 §6.4.2/6 The switch statement [stmt.switch] (Emphasis mine):

> 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 ]

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmikkView Question on Stackoverflow
Solution 1 - C++Baum mit AugenView Answer on Stackoverflow
Solution 2 - C++PersixtyView Answer on Stackoverflow
Solution 3 - C++BeyelerStudiosView Answer on Stackoverflow
Solution 4 - C++Nikola DimitroffView Answer on Stackoverflow
Solution 5 - C++Yakov GalkaView Answer on Stackoverflow
Solution 6 - C++Richard CordenView Answer on Stackoverflow
Solution 7 - C++101010View Answer on Stackoverflow