这不是未定义行为,它只是 C89 和 C99 之间 C 语言标准的重大变化。
在 C89 中,像 4008636143 这样的整数常量不适合int
or long int
但确实适合unsigned int
是无符号的,但在 C99 中,它们要么是long int
or long long int
(取决于能够容纳该值的最小的那个)。因此,所有表达式均使用 64 位进行计算,从而导致错误的答案。
Visual Studio 是 C89 编译器,因此会产生 C89 行为,但 Ideone 链接正在 C99 模式下编译。
如果您使用 GCC 进行编译,这一点会变得更加明显-Wall
:
test.c: In function ‘divisible15’:
test.c:8:3: warning: this decimal constant is unsigned only in ISO C90
来自 C89 §3.1.3.2:
整型常量的类型是对应的第一个常量
可以在其中表示其值的列表。不带后缀的十进制:int,
长整型,无符号长整型;无后缀的八进制或十六进制:int,
无符号整型、长整型、无符号长整型; [...]
C99 §6.4.4.1/5-6:
5) 整型常量的类型是其值可以在其对应列表中的第一个
被代表。
Suffix | Decimal Constant | Octal or Hexadecimal Constant
-------+------------------+------------------------------
none | int | int
| long int | unsigned int
| long long int | long int
| | unsigned long int
| | long long int
| | unsigned long long int
-------+------------------+------------------------------
[...]
6) 如果整型常量不能用其列表中的任何类型表示,则它可能有一个
扩展整数类型,如果扩展整数类型可以表示其值。如果所有的
常量列表中的类型是有符号的,扩展整数类型也应有符号。 [...]
为了完整起见,C++03 实际上确实有未定义的行为,用于当整数常量太大而无法容纳在一个整数中时。long int
。来自 C++03 §2.13.1/2:
整数文字的类型取决于其形式、值和后缀。如果是十进制且没有后缀,则有
第一种类型可以表示其值:int
, long int
;如果该值无法表示
作为一个long int
,行为未定义。如果它是八进制或十六进制并且没有后缀,则它具有
第一种可以表示其值的类型:int
, unsigned int
, long int
, unsigned
long int
. [...]
C++11 行为与 C99 相同,请参阅 C++11 §2.14.2/3。
为了确保代码在编译为 C89、C99、C++03 和 C++11 时表现一致,简单的修复方法是通过在常量 4008636143 后添加后缀来使其无符号u
as 4008636143u
.