C++20 has handy [[likely]]
/[[unlikely]]
attributes which guide code generation. For example, you can specify a branch is likely to be taken by:
if (b) [[likely]] { /*...*/ }
Similarly, it is possible to use these attributes in switch
statements . . . somehow? The documentation suggests the following example (slightly formatted):
switch (i) {
case 1:
[[fallthrough]];
[[likely]] case 2:
return 1;
}
The implication is clearly that the [[likely]]
/[[unlikely]]
goes before the case
statement. The internet seems to almost universally promulgate this usage.
However, consider the following similar code (all I've done is move the [[likely]]
to the other case
):
switch (i) {
[[likely]] case 1:
[[fallthrough]];
case 2:
return 1;
}
This fails to compile on clang! While that may be related to a compiler bug with [[fallthrough]]
, it got me looking at the standards. The relevant standard has the following example (see §VII):
implementations are encouraged to optimize for that case being executed (eg. a having the value 1 in the following code):
switch (a) {
case 1: [[likely]]
foo();
break;
//...
}
That is, the attribute comes after the case label, not before.
So . . . which is it? Offhand, I'd expect the standard to be correct, but that is actually a proposal, not the real standard AFAICT—it could have been changed since. And, I'd expect the documentation, if nothing else, to be correct at least about the fundamental syntax—except that it doesn't even compile.
The switch/case statement in the c language is defined by the language specification to use an int value, so you can not use a float value. The value of the 'expression' in a switch-case statement must be an integer, char, short, long. Float and double are not allowed.
A switch statement can have an optional default case, which must appear at the end of the switch. The default case can be used for performing a task when none of the cases is true. No break is needed in the default case.
1) Break: This keyword is used to stop the execution inside a switch block. It helps to terminate the switch block and break out of it. 2) Default: This keyword is used to specify the set of statements to execute if there is no case match.
Similarly, it is possible to use these attributes in switch statements . . . somehow? The documentation suggests the following example (slightly formatted): switch (i) { case 1: [ [fallthrough]]; [ [likely]] case 2: return 1; } The implication is clearly that the [ [likely]] / [ [unlikely]] goes before the case statement.
Syntax. The syntax for a switch statement in C programming language is as follows −. The expression used in a switch statement must have an integral or enumerated type, or be of a class type in which the class has a single conversion function to an integral or enumerated type. You can have any number of case statements within a switch.
This documents ( cppreference) only gave an example on applying them to a switch-case statement. This switch-case example compiles perfectly with my compiler (g++-7.2) so I assume the compiler has implemented this feature, though it's not yet officially introduced in current C++ standards.
If the use of the likely and unlikely macros seemed a bit ad hoc, watch out for the C++ 20 [ [likely]] and [ [unlikely]] attributes. These attributes would also be supported in switch-statement. The C++ 20 proposal for the [ [likely]] and [ [unlikely]] describes the advantages of giving direct hints to the compiler.
Both examples are valid, and Clang is exhibiting a bug. The relevant verbiage from the last standard draft for C++20 is
[dcl.attr.likelihood]
1 The attribute-tokens
likely
andunlikely
may be applied to labels or statements.
Where the relevant grammar productions for statements and labeled statements have an attribute specifier sequence at the appropriate locations.
[stmt.pre]
statement: labeled-statement attribute-specifier-seq expression-statement attribute-specifier-seq compound-statement attribute-specifier-seq selection-statement attribute-specifier-seq iteration-statement attribute-specifier-seq jump-statement declaration-statement attribute-specifier-seq try-block
[stmt.label]
labeled-statement: attribute-specifier-seq identifier : statement attribute-specifier-seq case constant-expression : statement attribute-specifier-seq default : statement
In
switch (i) {
case 1:
[[fallthrough]];
[[likely]] case 2:
return 1;
}
The attribute applies to case 2:
wheras in
switch (a) {
case 1: [[likely]]
foo();
break;
//...
}
it applies to the statement foo();
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With