C语言中整型提升问题

前言

  今天有人问了 Shaun 一个移位的问题,就是下面这段 C 语言代码:

1
2
unsigned short a = 0xffff;
printf("%#hx\n", a << 4 >> 8 << 4);

你认为会输出什么结果? ੧ಡ ⌣ ಡ੭

解答篇

  正确答案是:0xfff0。恐怕有一部分会像 Shaun 一样觉得答案就是 0xff0 才对,还像模像样的给出对应的说法:看 a 首先向左移四位,即去掉最左边的 f,右边补 4 个 0 变成这样 0xfff0;然后再向右移 8 位,a 将会变成这样 0x00ff;最后向左移四位,得到 0x0ff0,所以应该输出 0xff0但是,正确答案终究是正确答案。之所以会输出正确答案,是因为这里面还有一个整型提升。所谓的整型提升就是:

在一个表达式中,如果int能够表示原始类型中的所有数值,那么这个数值就被转成int型,否则,它被转成unsigned int型。这种规则被称为整型提升。所有其它类型都不会被整型提升改变。

  所以在 a << 4 >> 8 << 4 中,会先将 a 提升为 int 型,即 a 会变成 0x0000ffff,接着向左移四位,a 变成 0x000ffff0,再向右移 8 位,变成 0x00000fff,最后向左移 4 位,变成 0x0000fff0,最后为了输出,再做一个隐式的类型转换(由 int 转 unsigned short),得到 0xfff0,所以最后输出 0xfff0

后记

  这个问题是一个刚入大学的童靴问 Shaun 的,刚问 Shaun 时 Shaun 还没反应过来,后来才想起有整型提升这么回事 o(╯□╰)o。btw,这位童靴主要是想去掉高 4 位和低 4 位只取中间 8 位的值,其实最简单的办法就是直接 a & 0x0ff0,这样管它有没有整型提升,肯定能得到中间 8 位的值 (╯▽╰)。

参考资料

[1] C语言进阶:整型提升http://blog.csdn.net/mishifangxiangdefeng/article/category/1058873

[2] 对 unsigned char 先左移 后右移 可以出现两种结果