The following program prints "unknown" when compiled with different compilers. Why is that so?
#include "stdio.h"
const char OPTION = (char)(unsigned char)253;
int main(int argc, char* argv[])
{
unsigned char c = 253;
switch (c)
{
case OPTION:
printf("option\n");
break;
default:
printf("unknown\n");
break;
}
return 0;
}
When looking at the C++ standard (N3690 2013-05-05) I see a clause for switch:
6.4.2 The switch statement
2 The condition shall be of integral type, enumeration type, or class type. If of class type, the condition is contextually implicitly converted (Clause 4) to an integral or enumeration type. Integral promotions are performed. Any statement within the switch statement can be labeled with one or more case labels as follows:
case constant-expression :
where the constant-expression shall be a converted constant expression (5.19) of the promoted type of the switch condition. No two of the case constants in the same switch shall have the same value after conversion to the promoted type of the switch condition.
The referenced conversion clause:
4 Standard conversions
2 [ Note: expressions with a given type will be implicitly converted to other types in several contexts:
[...]
— When used in the expression of a switch statement. The destination type is integral (6.4).
[...]
—end note ]
Variable c is of type unsigned char, which is an integral type. So no promotion should be necessary!?
If the promoted type were unsigned char
I would expect a comparison like c == (unsigned char)OPTION
which would yield true. If the promoted type were int
I would expect a comparison like (int)c == (int)OPTION)
which clearly yields false.
My questions are: What is the promoted type used in the above program? What are the relevant clauses in the C and C++ standards?
The promoted type will be int
, as described in the following section:
4.5p1
Integral promotions[conv.prom]
A prvalue of an integer type other than
bool,
char16_t,
char32_t,
orwchar_t
whose integer conversion rank (4.13) is less than the rank ofint
can be converted to a prvalue of typeint
ifint
can represent all the values of the source type; otherwise, the source prvalue can be converted to a prvalue of typeunsigned int
.
It's implementation defined whether char is signed, or unsigned, as can be read in the following section of the Standard;
3.9.1p1
Fundamental types[basic.fundamental]
It is implementation-defined whether a
char
can hold negative values. Characters can be explicitly declaredsigned
orunsigned
....
In any particular implementation, a plain
char
object can take on either the same values as asigned char
or anunsigned char;
which one is implementation-defined.
The previous quoted section means that the cast to char
on the following line doesn't have to yield the value of 253
.
const char OPTION = (char)(unsigned char)253;
If char is made to be able to hold negative values on a platform where a char is 8bit, 253
won't fit and most likely the value of OPTION
will be -3
after initialization.
The switch, after integral promotion, in your post is semantically equivalent to the below if-else-statement, since we have one condition and a default case.
unsigned char c = 253;
// .---------.-------------------- integral promotion
// v v
if ((int)c == (int)OPTION) {
printf ("OPTION\n");
} else {
printf ("DEFAULT\n");
}
Depending on the underlying implementation OPTION
might be equal to either 253
, or -3
; yielding the behavior your described.
Note: All standard quotations in this post are from the final C++11 Standard (draft) n3337.
The relevant part here is "Integral promotions are performed."
The short version of that is that types smaller than an int are promoted to an int (or an unsigned int if an int couldn't represent the full range of the values).
So you have c
promoted to an int, which is 253. And you have OPTION
with a value of -3 promoted to an int, which is -3. (The sign of a char
is platform dependent though, so this program can behave differently on different platforms. The range of values a char can hold is platform dependent too, albeit a conversion of 253 to -3 will happen on 2s-complement platforms with 8 bit signed char, which are common.)
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