C++ 无符号到有符号的转换
考虑以下几点:C++ 无符号到有符号的转换,c++,C++,考虑以下几点: #include <iostream> int main() { unsigned int x = 3; unsigned int y = 5; std::cout << "a: " << x - y << std::endl; std::cout << "b: " << ((int)x) - y << std::endl; std:
#include <iostream>
int main() {
unsigned int x = 3;
unsigned int y = 5;
std::cout << "a: " << x - y << std::endl;
std::cout << "b: " << ((int)x) - y << std::endl;
std::cout << "c: " << x - ((int)y) << std::endl;
std::cout << "d: " << ((int)x) - ((int)y) << std::endl;
}
$ g++ -Wconversion -Wall uint_stackoverflow.cc -o uint_stackoverflow && ./uint_stackoverflow
a: 4294967294
b: 4294967294
c: 4294967294
d: -2
#包括
int main(){
无符号整数x=3;
无符号整数y=5;
std::cout在算术运算中,如果任何一个操作数无符号
,另一个操作数将转换为无符号
(如果其有符号
),运算结果也将是无符号
此外,将无符号
强制转换为有符号
,然后执行该操作不会改变操作数的位表示形式。在二补结构(即几乎所有现代结构)上,(int)x
与x
具有相同的位表示形式,只有在计算其十进制值时,它们的解释才会改变。但重要的一点是,算术运算是在位表示形式上执行的(而不是在其十进制值上执行的)。而且由于转换不会更改位表示,因此结果的位表示也不会更改
C++03标准在§5/9中规定:
许多二进制运算符
算术或枚举的操作数
类型原因转换和产量
结果类型以类似的方式
目的是产生一种普通类型,
这也是结果的类型。
这种模式被称为普通模式
算术转换,即
定义如下:
[……]
否则,如果任一操作数为
未签名的,另一个应转换
要取消签名
这是因为在执行隐式转换时存在数据类型的继承权,无符号整数的优先级高于有符号整数,因此b和c被转换回无符号整数,这就是为什么您看到的结果是无符号整数
如果你不确定类型,但知道你想要的结果类型,那么你应该像在d中一样同时施放x和y
这对类型转换有很好的解释:
像往常一样引用标准
对于C++98,§[expr]/9:
许多二进制运算符
算术或枚举的操作数
类型原因转换和产量
结果类型以类似的方式
目的是产生一种普通类型,
这也是结果的类型。
这种模式被称为普通模式
算术转换,即
定义如下:
- 如果任一操作数的类型为长双精度
,则应转换另一个操作数
到长双精度
加倍
浮点
,则应转换另一个操作数
到浮动
unsigned long
长int
可以表示所有
无符号int
的值
无符号整数
应转换为
long int
;否则两个操作数
应转换为无符号长
int
长
,则应转换另一个操作数
到长
无符号
,则另一个操作数应为
已转换为未签名的
int
]
基本上可以概括为
long-double
double
float
unsigned-long
long
unsigned
int
- (小于
的类型将转换为int
)int
在第5项之后,文本更改为C++0x(§[expr]/10),但对OP代码的影响是相同的:
int
将转换为无符号
注意,将大的无符号
转换为有符号
显然是不可移植的。C++11标准规定:如果目标类型是有符号的,则如果源整数可以在目标类型中表示,则该值不会更改。否则,结果是实现定义的。"算术是在C中的值上执行的,而不是位表示本身。choose two的补码表示法的优点之一是,有符号算术可以使用与无符号算术相同的指令完成。这与强制转换是否更改表示法无关,但实际上,这必须在不要使用2的补码。在第一段中,最好明确你的意思是unsigned int
,而不是一般的无符号类型(例如,如果unsigned short
和short
是操作数,那么它们将升级为int
,而不是任何无符号)