什么促销类型用于switch-case表达式比较?
使用不同的编译器编译时,以下程序打印“unknown”。 为什么会这样?
#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; }
在查看C ++标准(N3690 2013-05-05)时,我看到了一个switch子句:
6.4.2 switch语句
2条件应为整数类型,枚举类型或类类型。 如果是类类型,则将条件在上下文中隐式转换(第4节)为整数或枚举类型。 执行整体促销。 switch语句中的任何语句都可以用一个或多个case标签标记,如下所示:
case constant-expression :
其中constant-expression应为切换条件的提升类型的转换常量表达式(5.19)。 在转换为提升类型的开关条件后,同一开关中的两个shell常量应具有相同的值。
引用的转换条款:
4标准转换
2 [注意:具有给定类型的表达式将在多个上下文中隐式转换为其他类型:
[…]
– 用于表达switch语句时。 目的地类型是整数(6.4)。
[…]
– 尾注]
变量c的类型为unsigned char,它是一个整数类型。 所以不需要晋升!?
如果提升的类型是unsigned char
我希望比较像c == (unsigned char)OPTION
,它将产生true。 如果提升的类型是int
我会期望像(int)c == (int)OPTION)
这样的比较明显产生错误。
我的问题是:上述计划中使用的推广类型是什么? C和C ++标准中的相关条款是什么?
涉及哪些类型?
提升类型将为int
,如以下部分所述:
4.5p1
整体促销[conv.prom]
如果
int
可以表示源类型的所有值,则整数转换等级(4.13)小于int
的等级的除bool,
char16_t,
char32_t,
或wchar_t
的整数类型的prvalue可以转换为int
类型的prvalue ; 否则,源prvalue可以转换为unsigned int
类型的prvalue。
为什么代码在不同平台上的行为不同?
它的实现定义了char是有符号的还是无符号的,可以在标准的以下部分中阅读;
3.9.1p1
基本类型[basic.fundamental]
实现定义
char
是否可以保存负值。 字符可以显式声明为有signed
或unsigned
。…
在任何特定实现中,普通
char
对象可以采用与signed char
或unsigned char;
相同的值unsigned char;
哪一个是实现定义的。
那有什么关系?
之前引用的部分意味着以下行中的转换为char
不必产生值253
。
const char OPTION = (char)(unsigned char)253;
如果使char能够在char为8bit的平台上保持负值,则253
将不适合,并且很可能初始化后OPTION
的值将为-3
。
换一种说法…
整数提升后,在你的post中的开关在语义上等同于下面的if-else语句 ,因为我们有一个条件和一个默认情况。
unsigned char c = 253; // .---------.-------------------- integral promotion // vv if ((int)c == (int)OPTION) { printf ("OPTION\n"); } else { printf ("DEFAULT\n"); }
根据底层实现, OPTION
可能等于253
或-3
; 产生你描述的行为。
注意 :本文中的所有标准引用均来自最终的C ++ 11标准(草案) n3337 。
这里的相关部分是“执行整体促销”。
它的简短版本是小于int的类型被提升为int(如果int不能表示整个值范围,则为unsigned int)。
所以你将c
提升为一个int,即253.你有一个值为-3的OPTION
提升为一个int,即-3。 ( char
的符号虽然与平台有关,但是这个程序在不同的平台上的行为可能不同.Char可以容纳的值范围也取决于平台,尽管在2s补码平台上会发生253到-3的转换。 8位签名字符,很常见。)
正如报价中所述,您引用了“整体促销活动”。 所以在这个表达中
switch (c)
c将转换为int类型,其值为253,因为c是无符号整数对象。
在这个标签
case OPTION:
因为OPTION是有符号字符(我认为默认情况下char表现为有符号字符)然后将传播符号位。
因此控件将传递给label default
因为(int)(unsigned char)253不等于(int)(signed char)253。