9

我写了以下c代码:

#include <stdio.h>

int main () {
  printf("%d\n", -1 >> 8);
  return 0;
}

我使用 -m32 标志在我的 x86_64 上使用 gcc 4.6.3 编译此代码。正如我所料,我得到 -1 打印出来,移位发生在算术上,使用二进制补码表示导致 -1。

现在,如果我改为写

printf("%d\n", 0xFFFFFFFF >> 8);

我得到 16777215。我本来希望这个常量被解释为一个 int(有符号),然后转换为算术,这将再次导致 -1。我查看了最新的 C 标准,但我似乎无法理解为什么会这样。有任何想法吗?

4

2 回答 2

17

根据 C99 标准 (6.4.4.1),十六进制常量将是此列表中可以表示它们的第一个类型:

int
unsigned int
long int
unsigned long int
long long int
unsigned long long int

十六进制文字0xFFFFFFFF不适合 an int(可以将值保存-0x800000000x7FFFFFFF),但适合unsigned int,因此其类型将是无符号的。将无符号值右移0xFFFFFFFF8 得到16777215.

于 2012-09-19T17:24:59.513 回答
11

未修饰的整数文字根据它们是否为十进制而具有不同的类型(C11 中的 6.4.4.1/5,C++11 中的表 6):

  • 十进制文字,即[1-9][0-9]*,总是有符号的。

  • 十六进制和八进制文字要么是有符号的,要么是无符号的。如果值对于有符号类型来说太大,但小到足以容纳相同宽度的无符号类型,则它将是无符号的。(这就是您的十六进制常量所发生的事情。)

右移负整数是实现定义的,你碰巧得到符号扩展。右移无符号值是简单的除以二。

于 2012-09-19T17:17:47.790 回答