什么促销类型用于switch-case表达式比较?

Wer*_*nze 4 c c++ language-lawyer

使用不同的编译器编译时,以下程序打印"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;
}
Run Code Online (Sandbox Code Playgroud)

在查看C++标准(N3690 2013-05-05)时,我看到了一个switch子句:

6.4.2 switch语句

2条件应为整数类型,枚举类型或类类型.如果是类类型,则将条件在上下文中隐式转换(第4节)为整数或枚举类型.执行整体促销.switch语句中的任何语句都可以用一个或多个case标签标记,如下所示:

case constant-expression :  
Run Code Online (Sandbox Code Playgroud)

其中constant-expression应该是切换条件的提升类型的转换常量表达式(5.19).在转换为提升类型的开关条件后,同一开关中的两个外壳常数不应具有相同的值.

引用的转换条款:

4标准转换

2 [注意:具有给定类型的表达式将在多个上下文中隐式转换为其他类型:
[...]
- 在switch语句的表达式中使用时.目的地类型是积分(6.4).
[...] - 结束
说明]

变量c的类型为unsigned char,它是一个整数类型.所以不需要晋升!?

如果推广类型是unsigned char我希望比较c == (unsigned char)OPTION,如果产生真实.如果提升类型,int我会期望比较(int)c == (int)OPTION)明显产生错误.

我的问题是:上述计划中使用的推广类型是什么?C和C++标准中的相关条款是什么?

Fil*_*efp 6

涉及哪些类型?

升级类型将int如以下部分所述:

4.5p1 整体促销 [conv.prom]

整数型的以外的prvalue bool, char16_t, char32_t,wchar_t其整数转换秩(4.13)小于的秩int可以被转换成类型的prvalue int如果int可以表示源类型的所有值; 否则,源prvalue可以转换为类型的prvalue unsigned int.


为什么代码在不同平台上的表现不同?

它的实现定义了char是有符号的还是无符号的,可以在标准的以下部分中阅读;

3.9.1p1 基本类型 [basic.fundamental]

它是实现定义的,是否char可以保持负值.可以显式声明字符signedunsigned.

...

在任何特定实现中,普通char对象可以采用与a signed charunsigned char;实现定义的值相同的值.


那有什么关系?

之前引用的部分意味着char在以下行上的强制转换不必产生值253.

const char OPTION = (char)(unsigned char)253;
Run Code Online (Sandbox Code Playgroud)

如果char被设置为能够在char为8bit 的平台上保持负值,253则不适合并且很可能OPTION-3初始化之后的值.


换一种说法...

在整体提升之后,在你的帖子中的开关在语义上等同于下面的if-else语句,因为我们有一个条件和一个默认情况.

unsigned char c = 253;

//   .---------.-------------------- integral promotion
//   v         v
if ((int)c == (int)OPTION) {
  printf ("OPTION\n");
} else {
  printf ("DEFAULT\n");
}
Run Code Online (Sandbox Code Playgroud)

根据底层实现OPTION可能等于253,或-3; 产生你描述的行为.


注意:本文中的所有标准引用均来自最终的C++ 11标准(草案) n3337.