99网
您的当前位置:首页有符号数和无符号数之间的转换(2020)C

有符号数和无符号数之间的转换(2020)C

来源:99网

有符号数和无符号数之间的转换

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:///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 << "unmax>-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==unmax" << 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

unmax>-1

-1

un128max==unmax

un128max>-1

16 8 4 16 16


截图:

将负数转换成无符号数可能会得到0(小端法机器)

因篇幅问题不能全部显示,请点此查看更多更全内容