C和C++中的无符号数和有符号数 位扩展

C和C++中的无符号数和有符号数 位扩展

这里参照《深入理解计算机系统》

先引入几个函数:

#include <stdio.h>

typedef unsigned char * byte_pointer;

void show_bytes(byte_pointer start, size_t len)
{
    size_t i;
    for(i = 0; i < len; i++)
    {   
        printf("%.2x ", start[len - 1 - i]);
    }   
    printf("\n");
}

void show_int(int x)
{
    show_bytes((byte_pointer)&x, sizeof(int));
}

void show_float(float x)
{
    show_bytes((byte_pointer)&x, sizeof(float));
}

void show_pointer(void * x)
{
    show_bytes((byte_pointer)&x, sizeof(void *));
}

这几个函数用来将数据拆成字节,然后打印出来;


无符号数和有符号数之间的算术运算操作

C语言会隐式地将有符号参数强制转换成无符号数,然后进行算术运算。对于标准的算术运算来说并无多大差异,但是对于像<和>这样的关系运算符来说,它会导致非直观的结果。我们可以引入无符号数常量和有符号数常量进行举例。

表达式 类型 求值
0 == 0U 无符号 1
-1 < 0 有符号 1
-1 < 0U 无符号 0*
2147483647 > -2147483647-1 有符号 1
2147483647U >-214783647-1 无符号 0*
2147483647 > (int)2147483648U 有符号 1*
-1 > -2 有符号 1
(unsigned)-1 > -2 无符号 1

注:带*的为非直观的情况。


扩展一个数字的位表示

有符号数按照符号扩展的形式扩展高位,无符号数按照零扩展的方式扩展高位。

即 有符号数扩展时高位全部以原来的最高位(符号位)补齐,无符号数扩展时高位全部以0补齐。

扩展发生在将小数据类型转换成大数据类型时,例如short int 转换成 long int类型。

注意扩展之前是无符号数,则扩展按照零扩展的方式,即使存储扩展结果的是有符号数,

扩展之前是有符号数的,则扩展按照符号扩展方式,即使存储扩展结果的是无符号数:

#include <iostream>
#include <cstdio>

using namespace std;
typedef unsigned char * byte_pointer;

void show_bytes(byte_pointer start, size_t len)
{
    size_t i;
    for(i = 0; i < len; i++)
    {   
        printf("%.2x ", start[len - 1 - i]);
    }   
    printf("\n");
}

int main()
{
    long long data = (unsigned int)0x80000000;
    show_bytes((byte_pointer)&data, sizeof(data));
    unsigned long long udata = (unsigned int)0x80000000;
    show_bytes((byte_pointer)&udata, sizeof(udata));

    long long data2 = (int)0x80000000;
    show_bytes((byte_pointer)&data2, sizeof(data2));
    unsigned long long udata2 = (int)0x80000000;
    show_bytes((byte_pointer)&udata2, sizeof(udata2));
    return 0;
}

换句话说,扩展方式只与原数据的类型有关,与要转换成的类型无关,上例中,不管unsigned int转换成long long类型还是unsigned long long类型都按照零扩展方式,同样,无论int转换成long long还是unsigned long long都采取符号扩展的方式。

运行结果为:

00 00 00 00 80 00 00 00 
00 00 00 00 80 00 00 00 
ff ff ff ff 80 00 00 00 
ff ff ff ff 80 00 00 00 

知道了上述两个规则,下面我们分析一个小例子:

unsigned long long data = 100;

unsigned int ux = -1;

int x = -1;

data += ux; //求data的值

data = 100;

data += x;//求data的值

上述例子中data的值分别是什么,

分析如下:按照规则1,有无符号数参与的算数运算之前C语言会把有符号的参数强制转换成无符号的参数,data +=x;中x的值为0xffffffff,强制转换之前要进行位扩展,从4字节扩展成8字节,x是有符号数,且原最高位为1, 所以新的高4字节全部为1,0xff ff ff ff ff ff ff ff +100, 溢出后,结果为99,0x63;

data += ux; 中ux位无符号数,所以按照零扩展方式,扩展后还是0xff ff ff ff, 加100 结果为0x 01 00 00 00 63

第一处data 为0x 01 00 00 00 63,第二处data为 0x63

验证如下:

int main()
{
    unsigned long long data = 100;

    unsigned int ux = -1; 

    int x = -1; 

    data += ux; //求data的值
    show_bytes((byte_pointer)&data, sizeof(data));
    data = 100;
    data += x;//求data的值
    show_bytes((byte_pointer)&data, sizeof(data));
    return 0;
}

运行结果为

00 00 00 01 00 00 00 63 
00 00 00 00 00 00 00 63 


猜你喜欢

转载自blog.csdn.net/xiaoyink/article/details/79856078