C++整数常量的类型

3
根据MSDN (整数类型 - VC2008)的描述:

没有后缀的十进制常量的类型为int、long int或unsigned long int。能够表示该常量值的三种类型中,第一个被赋予该常量的类型。

Visual C++ 2008上运行以下代码:
void verify_type(int a){printf("int [%i/%#x]\n", a, a);}
void verify_type(unsigned int a){printf("uint [%u/%#x]\n", a, a);}
void verify_type(long a){printf("long [%li/%#lx]\n", a, a);}
void verify_type(unsigned long a){printf("ulong [%lu/%#lx]\n", a, a);}
void verify_type(long long a){printf("long long [%lli/%#llx]\n", a, a);}
void verify_type(unsigned long long a){printf("unsigned long long [%llu/%#llx]\n", a, a);}

int _tmain(int argc, _TCHAR* argv[])
{
    printf("sizeof(int) %i\n", sizeof(int));
    printf("sizeof(long) %i\n", sizeof(long));
    printf("sizeof(long long) %i\n\n", sizeof(long long));

    verify_type(-2147483647);
    verify_type(-2147483648);

    getchar();
    return 0;
}

我得到了这个:
sizeof(int) 4
sizeof(long) 4
sizeof(long long) 8

int [-2147483647/0x80000001]
ulong [2147483648/0x80000000]  <------ Why ulong?

我期望 const -2147483648 () 应该是 int 类型。为什么我得到的是 ulong 而不是 int?

我已经编程很长时间了,直到今天我才意识到 + 或 - 不是整数常量的一部分。这个提示解释了一切。

      integer-constant:
              decimal-constant integer-suffix<opt>
              octal-constant integer-suffix<opt>
              hexadecimal-constant integer-suffix<opt>

      decimal-constant:
              nonzero-digit
              decimal-constant digit

      octal-constant:
              0
              octal-constant octal-digit

      hexadecimal-constant:
              0x  hexadecimal-digit
              0X  hexadecimal-digit
              hexadecimal-constant hexadecimal-digit

      nonzero-digit: one of
              1  2  3  4  5  6  7  8  9

      octal-digit: one of
              0  1  2  3  4  5  6  7

      hexadecimal-digit: one of
              0  1  2  3  4  5  6  7  8  9
              a  b  c  d  e  f
              A  B  C  D  E  F

      integer-suffix:
              unsigned-suffix long-suffix<opt>
              long-suffix unsigned-suffix<opt>

      unsigned-suffix: one of
              u  U

      long-suffix: one of
              l  L

请注意,您的许多 printf 语句会导致未定义的行为。您不能将负值传递给 %x%lx - M.M
1
C语言中没有函数重载,所以这段代码无法在C中编译。这是一些C++的东西。 - Orace
@MattMcNabb,在老派的C++ ideone中给出了一个ulong:http://ideone.com/WGlarH,同时答案也非常好。 - Orace
@MikeofSST:编译器具有比32位值更丰富的表示形式。例如,它还具有类型(unsigned long)。这明确告诉编译器MSB不是符号位。编译器还具有表达式operator-(unsigned long) unsigned_long_literal(2147483648)。不,这个一元运算符operator-并不返回有符号长整型。 - MSalters
@MikeofSST:MSVC在这方面没有选择。行为是明确定义的。至于“4个字节”,那完全不相关。重载适用于精确类型,而不是sizeof(type)void foo(int)void foo(long)是不同的函数。 - MSalters
显示剩余10条评论
3个回答

5
您正在将一元运算符-应用于整数字面量2147483648。由于整数字面量是2^31,因此太大而无法适应32位int。在现代C++中,它应该被视为long long,因此您的结果令人惊讶。
我认为旧的C标准(long long之前)允许将一个过大的字面量解释为unsigned long类型,这与您所看到的一致。我看到您在帖子顶部引用的MSDN文档重复了这一点,所以这里肯定是发生了这种情况。

1
C++11之前,C++没有long long。我确定VS2008没有C++11。然而,微软可能已经添加了他们自己的int64类型作为扩展,并想出了一些处理常量的方法。 - M.M
1
OP链接的文档标题为“C常量”,因此可能不适用;但它与他展示的输出一致。也许编译器在4294967295之前使用C++03定义的常量,之后切换到long long。或者其他什么原因。 - M.M
@MattMcNabb:如果我没记错的话,MSVC 也是这样处理的。任何太大的字面量都会导致未定义行为。其中一种有效且合理的 UB 形式是具有类型 __int64 的整数字面量。 - MSalters

5
首先,-2147483648 不是一个整数常量,因为 - 是一个一元运算符,不是常量的一部分(至少在这个上下文中是这样)。2147483648 是一个整数常量,-2147483648 是涉及该常量的表达式。
由于 2147483648 不能表示为 intlong int,但可以表示为 unsigned long int,因此它得到类型 unsigned long int。将一元 - 运算符应用于 unsigned long int 的结果也是 unsigned long int

5

-2147483648 不是一个整数字面量。它是应用于整数字面量 2147483648 的一元运算符 -。该字面量的值不适合 signed intsigned long,因此它具有类型 unsigned long。运算符 - 不会改变该类型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接