为什么长 l = 0x80000000是正数?

Why is long l = 0x80000000 a positive number?

本文关键字:0x80000000 为什么      更新时间:2023-10-16

在C++中,为什么long l = 0x80000000;是正的?

C++:
long l = 0x80000000; // l is positive. Why??
int i = 0x80000000;
long l = i; // l is negative

根据这个网站:https://en.cppreference.com/w/cpp/language/integer_literal,0x80000000应该是一个有符号的int,但它似乎不是这样,因为当它被分配给l符号扩展时不会发生。

Java:
long l = 0x80000000; // l is negative
int i = 0x80000000;
long l = i; // l is negative

另一方面,Java具有更一致的行为。

C++ 测试代码:

#include <stdio.h>
#include <string.h>
void print_sign(long l) {
if (l < 0) {
printf("Negativen");
} else if (l > 0) {
printf("Positiven");
} else {
printf("Zeron");
}    
}
int main() {
long l = -0x80000000;
print_sign(l); // Positive
long l2 = 0x80000000;
print_sign(l2); // Positive
int i =   0x80000000;
long l3 = i;
print_sign(l3); // Negative
int i2 =  -0x80000000;
long l4 = i2;
print_sign(l4); // Negative
}

从您的链接:"整数文本的类型是值可以容纳的第一种类型,来自类型列表,这取决于使用了哪个数字基数和哪个整数后缀。 对于十六进制值,列出整数,无符号整数...

编译器使用 32 位整数,因此最大(有符号(整数为 0x7FFFFFFF。已签名的 int 不能表示0x8000000的原因...0xFFFFFFF是它需要其 32 位的 2^32 个可能值中的一些来表示负数。 但是,0x80000000适合 32 位无符号 int。您的编译器使用 64 位长整型,最多可容纳 0x7FFF FFFF FFFF FFFF,因此0x80000000也适合有符号长整型,因此长l是正值0x80000000。

另一方面,inti是一个有符号的 int,根本不适合0x80000000,因此会发生未定义的行为。当有符号数太大而无法放入C++时,经常发生的情况是使用双补运算并且数字四舍五入为一个大的负数。(不要依赖这种行为;众所周知,优化会打破这种行为(。无论如何,在这种情况下,两者的补体行为似乎确实发生了,导致i是负面的。

在示例代码中,您同时使用 0x80000000 和 -0x80000000,在每种情况下,它们都有相同的结果。事实上,它们是一样的。回想一下,0x8000000是一个无符号的 int。2003 C++标准在 5.3.1c7 中说:"无符号量的负数是通过从 2^n 中减去其值来计算的,其中 n 是提升操作数中的位数。 0x80000000正好是 2^31,因此 -0x80000000 是 2^32-2^31=2^31。为了获得预期的行为,我们必须使用 -(long(0x80000000 代替。

在SO上很棒的人的帮助下,我想我现在可以回答我自己的问题了:

只是为了纠正0x80000000不能放入整数的概念: 可以在没有丢失或未定义行为的情况下存储0x80000000int的值(假设sizeof(int) == 4(。下面的代码可以演示此行为:

#include <limits.h>
#include <stdio.h>
int main() {
int i = INT_MIN;
printf("%Xn", i);
return 0;
}

不过,将文字0x80000000分配给变量并不微妙。

其他人(除了@Daniel Langr(没有提到的是C++没有否定文字的概念。

没有负整数文本。-1等表达式将一元减号运算符应用于文本表示的值,这可能涉及隐式类型转换。

考虑到这一点,文字0x80000000始终被视为正数。否定是在确定大小和符号之后进行的。这很重要:否定不会影响文字的无符号/有符号,只有基数和值会影响。0x80000000太大而无法容纳有符号整数,因此C++尝试使用下一个适用的类型:unsigned int,然后成功。C++尝试的类型顺序取决于文字的基础以及它可能有或没有的任何后缀。

下表列出如下:https://en.cppreference.com/w/cpp/language/integer_literal

因此,考虑到这条规则,让我们制定一些示例:

  1. -2147483648: 被视为long int,因为它不适合int
  2. 2147483648:被视为long int,因为C++不认为unsigned int是十进制文字的候选者。
  3. 0x80000000:被视为unsigned int,因为C++认为unsigned int是非十进制文字的候选者。
  4. (-2147483647 - 1): 被视为int。这通常是定义INT_MIN以将文本的类型保留为int的方式。这是将-2147483648作为int的类型安全方式。
  5. -0x80000000: 即使存在否定,也被视为unsigned int。但是,否定任何unsigned都是未定义的行为。
  6. -0x80000000l: 被视为long int,符号被正确否定。