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