Visual Studio 2015 - 编译器警告(等级2)C4146

9

我在代码中有以下这行

signed int test_case= -2147483648;

这会产生错误:

C4146对无符号类型应用一元负运算符,结果仍为无符号

但这仍然处于有符号整数类型的数据范围内:

__int32 signed、signed int、int -2,147,483,648 到 2,147,483,647

奇怪的是将其分配为 signed long 会导致相同的错误,即:

signed long test_case= -2147483648;

下面的更改可以编译成功:
signed int test_case= -2147483647;

signed int test_case= 2147483649;

signed long test_case= -214748364800;
  • 有人看到过Visual Studio 2015编译器的这个问题吗?
  • 它是如何定义数据类型的?
  • 它如何进行范围检查?
  • 为什么它似乎忽略了“signed”赋值?

谢谢。


你自己写的:2,147,483,647 是最大的 int,所以对 2,147,483,648(应用了 -)不再是 intsigned long long test_case = -2147483648ll; - Pixelchemist
2个回答

12

这是一个编译器错误。

首先要注意的是:-2147483648不是字面量,C++中没有负字面量。

-2147483648是一个由2147483648和一元负号运算符组成的可在编译时求值的常量表达式。

在针对 Windows x64 的 MSVC 上(其中 int 和 long 都是32位),2147483648 应该是 long long int 类型,因此 -2147483648 也应该是 long long int。我理解标准要求使用带符号类型,除非使用十六进制或八进制字面量。

在这种情况下,将其强制转换为 signed int 是明确定义的,因为您的目标平台具有32位二进制补码 int 类型。

更多参考:请参阅http://en.cppreference.com/w/cpp/language/integer_literal


你的意思是标准规定如果 int 类型不够用,下一个级别应该是 long long 而不是 int 的无符号版本吗? - Humam Helfawi
确实如此。除非您使用十六进制或八进制表示法编写了字面量,否则它不能使用无符号类型。请参见http://en.cppreference.com/w/cpp/language/integer_literal中的“未标记”部分。 - Bathsheba
有趣!在 MSDN 上他们明确表示这是有意为之的事情! - Humam Helfawi
我的理解是他们没有正确地实现标准。 - Bathsheba
虽然将“long long”添加到C99中不会改变大多数未实际使用该类型的代码的行为,但它会改变其值介于ULNG_MAX + 1UL和ULNG_MAX之间的十进制文字的含义。一个重视与现有代码兼容性而非符合新标准的编译器可能会以与早期代码所期望的相同方式评估这样的十进制文字。 - supercat
显示剩余2条评论

8
由于这是编译器的错误,因此此答案仅适用于 MSVC,从iso C++的角度来看是错误的。有关正确和标准的答案,请参见@Bathsheba的答案。(我建议OP接受正确的答案,而不是本答案,以供未来读者参考)。

来自MSDN

评估数字2147483648。由于它大于最大整数值2147483647,所以2147483648的类型不是int,而是unsigned int。

换句话说,编译器将-2147483648处理为-2147483648而不是-2147483648。因此,2147483648部分被视为unsigned int,因为它比int更大。然后编译器应用了-运算符,导致出现此警告。

解决方案:

auto test_case= -2147483648ll;

1
但我正在尝试分配一个负数 -2147483648。 - Ninjawil
没有所谓的负数。它是 int(或 unit),以及减一元运算符。请查看我的编辑。 - Humam Helfawi
1
太好了!这很有效。为什么 signed long test_case= -214748364800; 没有产生相同的错误呢? - Ninjawil
214748364800比无符号整数更大,因此直接被视为long long。 (不确定,只是猜测-您需要一个将标准副本放在枕头下的人:D) - Humam Helfawi
signed int test_case = std::numeric_limits<int>::min(); 或者只需使用 auto test_case = std::numeric_limits<int>::min();,您不需要为 2^31 使用计算器。 - Andriy Tylychko
显示剩余4条评论

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