什么促销类型用于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是否可以保存负值。 字符可以显式声明为有signedunsigned

在任何特定实现中,普通char对象可以采用与signed charunsigned 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。