有符号数和无符号数之间的转换
C语言允许在各种不同的数字数据类型之间做强制类型转换。例如,假设变量x声明为int
,u声明为unsigned
。表达式(unsigned)x
会将x的值转换成一个无符号数值,而(int)u
将u的值转换成一个有符号整数。将有符号数强制类型转换成无符号数,或者反过来,会得到什么结果?从数学的角度来说,可以想象到几种不同的规则。很明显,对于在两种形式中都能表示的值,我们是想要保持不变的。另外一个方面,将负数转换成无符号数可能会得到0[^1]。如果转换的无符号数太大以至于超过了补码能够表示的范围,可能会得到该范围的最大值。不过,对于C语言的实现来说,对这个问题的回答都是从位级角度来看,而不是从数的角度。
比如说,考虑下面的代码:
short int v = -12345;
unsigned short uv = (unsigned short)v;
printf("v = %d, uv = %u\n",v,uv);
在一台采用补码的机器来说,上述代码会产生如下输出:
v = -12345, uv = 53191
原因如下:
首先对于有符号整型v来说,-12345在采用补码的机器上面存储的位模式为[1100 1111 1100 0111]
其次对于无符号整型uv来说,53191在采用补码的机器上面存储的位模式位[1100 1111 1100 0111]
还可以反过来检验:
/**十六进制表示写作0xcfc7的16位位模式既是-12345的补码表示,又是53191的无符号表示。同时注意:12345+53191 = 65536 = 2^16这个属性可以推广到给定位模式的两个数值(补码和无符号数)之间的关系。*/
#include <stdio.h>
int main()
{
unsigned short x = 0xcfc7;
short y = 0xcfc7;
printf("%u\n", x);
printf("%d\n", y);
return 0;
}
程序输出示例:
53191
-12345
综上,强制类型转换的结果保持位值不变,只是改变了解释这些位的方式。因为由上图可知,-12345的16位补码表示与53191的16位无符号表示是完全一致的。将short强制类型转换为unsigned short改变数值[解释这些位的方式],但是不改变位表示本身。
对于大多数C语言的实现,处理同样的字长的有符号数和无符号数之间相互转换的一般规则是:数值可能会改变,但是位模式不变。
对于不同字长的类型,其隐式转换会复杂的多,感谢评论区@Lily_Shayi:
#include <iostream>
#include <iomanip>
using namespace std;
inline void print_uint128_t(__uint128_t x){
if(x>9)
print_uint128_t(x/10);
putchar(x%10+'0');
}
inline void print_int128(__int128 x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
print_int128(x/10);
putchar(x%10+'0');
}
//参考链接:https://blog.csdn.net/shadandeajian/article/details/81843805
int main()
{
__uint128_t a = 340282366920938463463374607431768211455;
// 下面这条语句编译出错,__uint128_t无法使用cout直接输出
// cout << "cout << a: " << a << endl;
cout << "a: " << endl;
print_uint128_t(a);
cout << endl << endl;
cout << "__int128: 340282366920938463463374607431768211455: " << endl;
print_int128(340282366920938463463374607431768211455);
cout << endl;
cout << "__uint128_t: 340282366920938463463374607431768211455: " << endl;
print_uint128_t(340282366920938463463374607431768211455);
cout << endl << endl;
unsigned long long b = 18446744073709551615;
cout << "b: " << endl << b << endl << endl;
cout << "__int128: 18446744073709551615: " << endl;
print_int128(18446744073709551615);
cout << endl;
cout << "__uint128_t: 18446744073709551615: " << endl;
print_uint128_t(18446744073709551615);
cout << endl << endl;
cout << "__int128: b: " << endl;
print_int128(b);
cout << endl;
cout << "__uint128_t: b: " << endl;
print_uint128_t(b);
cout << endl << endl;
//
cout << "__int128: -1: " << endl;
print_int128(-1);
cout << endl;
cout << "__uint128_t: -1: " << endl; // **********
print_uint128_t(-1);
cout << endl << endl;
cout << "int -> unsigned long long -1: " << endl << (unsigned long long)-1 << endl << endl;
// __uint128_t vs __uint128_t
// 18446744073709551615 < 340282366920938463463374607431768211455 ?
if (a < -1)
cout << "a<-1" << endl << endl;
// unsigned long long vs unsigned long long
// 18446744073709551615 == 18446744073709551615 ?
if (b == -1)
cout << "b==-1" << endl << endl;
// __uint128_t vs __uint128_t
// 18446744073709551615 == 18446744073709551615 ?
if (a == b)
cout << "a==b" << endl << endl;
// __int128 vs __int128
// 18446744073709551615 > -1 ?
if (18446744073709551615 > -1)
cout << "un64max>-1" << endl << endl;
// -1
cout << (int)18446744073709551615 << endl << endl;
// int vs int
// -1 > -1 ?
if ((int)18446744073709551615 > (int)-1)
cout << "(int)18446744073709551615 > (int)-1" << endl << endl;
// __int128 vs __int128
// 18446744073709551615 == 18446744073709551615 ?
if (340282366920938463463374607431768211455 == 18446744073709551615)
cout << "un128max==un64max" << endl << endl;
// __int128 vs __int128
// 18446744073709551615 > -1 ?
if (340282366920938463463374607431768211455 > -1)
cout << "un128max>-1" << endl << endl;
// __uint128_t// unsigned long long// int// __int128 // __int128
cout << sizeof(a) << ' ' << sizeof(b) << ' ' << sizeof(-1)
<< ' ' << sizeof(18446744073709551615) << ' ' << sizeof(340282366920938463463374607431768211455) << endl << endl;
}
程序输出(Linux平台):
a:
18446744073709551615
__int128: 340282366920938463463374607431768211455:
18446744073709551615
__uint128_t: 340282366920938463463374607431768211455:
18446744073709551615
b:
18446744073709551615
__int128: 18446744073709551615:
18446744073709551615
__uint128_t: 18446744073709551615:
18446744073709551615
__int128: b:
18446744073709551615
__uint128_t: b:
18446744073709551615
__int128: -1:
-1
__uint128_t: -1:
340282366920938463463374607431768211455
int -> unsigned long long -1:
18446744073709551615
a<-1
b==-1
a==b
un64max>-1
-1
un128max==un64max
un128max>-1
16 8 4 16 16
截图: