为什么 0x8000000000000000LL 被 gcc 认为是 unsigned long long?

Why is 0x8000000000000000LL considered unsigned long long by gcc?

我正在编译一段代码,其中 0x8000000000000000LL 文字的值用于标识 unknown/unsupported 值。

LL 后缀表示该值应该被解释为 (signed) long long (int),但是 gcc (我用 4.8. 5 和 4.1.1) 表示该值的类型为 unsigned long long.

我在这里放了一个示例代码:

#include <stdio.h>

#define UNKNOWN 0x8000000000000000LL

int main(void){
  long long value = 1000;

  if ((unsigned long long) value == UNKNOWN) {
    puts("Yes, they are different!!");
  }

  if (value == (long long) UNKNOWN) {
    puts("Yes, they are different!!");
  }

  if (value == UNKNOWN) {
    puts("Yes, they are different!!");
  }
  return 0;
}

用这条命令编译的结果gcc -Wsign-compare ll.c是这样的:

ll.c: In function ‘main’:
ll.c:16:13: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
   if (value == UNKNOWN) {
             ^

为什么 0x8000000000000000LL 文字值被认为是无符号的?

因为它适用于十六进制或八进制且不适合后缀建议的整数类型的整数文字。

6.4.4.1p5:

The type of an integer constant is the first of the corresponding list in which its value can be represented.

请注意,与十进制整数文字不同,没有 u/U 后缀的十六进制和八进制文字可以在搜索合适的类型时翻转类型符号,然后再上升到下一个更高的 -排名有符号整数类型。