关于有符号数和无符号数的转换

1.引例:

今天在做了一道关于有符号数和无符号数相互转换及其左移/右移的问题,被它们之间的转换原理和位移原理搞得头大了。真的很后悔本科的时候没有认真学习《计算机组成原理》/《计算机操作系统》等计算机基础课程。以下是我根据相关知识回顾和整理的材料,如有和某某的文章有雷同之处,请勿见怪。另外也希望看到这篇文章的同志们能够有所收获吧。

 

#include <cstdio>
#include <iostream>
using namespace std;

int main()
{
    unsigned short int ui;
    signed short int si;
    ui = (unsigned short int)0x8000u;
    si = (signed short int)0x8000;
    printf("ui = %u\n", ui);
    printf("si = %d\n", si);
    ui = ui >> 1;
    si = si >> 1;
    printf("ui = %u\n", ui);
    printf("si = %d\n", si);
    cout << "------------------------------" << endl;

    ui = (unsigned short int)0x8000u;
    si = (signed short int)0x8000;
    printf("%u\n", ui);
    printf("%d\n", si);
    ui = ((signed short int)ui >> 1);
    si = ((unsigned short int)si >> 1);
    printf("%u\n", ui);
    printf("%d\n", si);
    cout << "------------------------------" << endl;

    ui = (unsigned short int)0x8000u;
    si = (signed short int)0x8000;
    printf("%u\n", ui);
    printf("%d\n", si);
    ui = ui << 1;
    si = si << 1;
    printf("%u\n", ui);
    printf("%d\n", si);
    cout << "-------------------------------" << endl;

    ui = (unsigned short int)0x8000u;
    si = (signed short int)0x8000;
    printf("%u\n", ui);
    printf("%d\n", si);
    ui = ((signed short int)ui << 1);
    si = ((unsigned short int)si << 1);
    printf("%u\n", ui);
    printf("%d\n", si);
    return 0;
}

显示结果:

2.概念
 在计算机中,可以区分正负类型的数,成为“有符号数”(signed);无正负类型的数(只有整数类型),成为“无符号数”(unsigned)。简明的说,无符号数就是其所有的位数都用来表示数值的大小,有符号数除最高位来表示数值的正负外(0表示正数;1表示负数),其余各位用来表示数值的大小。举个例子说明一下:十机制数 正数255  二进制表达形式:1111 1111

十机制数 负数-1     二进制表达形式:1111 1111 

可见-1的二进制的最高位为红色的1,可是为什么其表达形式为1111 1111而不是1000 0001呢?这就关于任何数在计算机内是以补码形式存储问题。下面会介绍的,在此先不详细说明了。

3.存储范围

从前面的介绍可以知道,由于有符号数的最高位被拿来用作符号位,所以它所能够表达的最大数值要小于无符号数所能够表达的最大数值。还是举个例子来说明一下吧:

无符号数:1111 1111 十进制值:255

有符号数:0111 1111 十进制值:127

这是有人可能会提出这样的疑问:有符号数所能够表达的数值范围会不会小于无符号数所能够表达的数值范围呢?

呵呵,答案是否定的!虽然有符号数在表达最大值上的能力减弱了,但是它能够表达负数。负数的个数可以弥补其不足。来让我们比较一下:

一个字节的无符号数的表达数值范围是:[0,255]

一个字节的有符号数的表达数值范围是:[-128,0),[0,127]

可见它们都能够表示256个数。

4.各种码(原码/反码/补码)

有些人也许会这样认为"-1"(双字节)在计算机中的表达形式为1000 0000 0000 0001,可是实际上不是的。计算机是以其补码的形式进行表达的,即“-1”(双字节)的表达形式是1111 1111 1111 1111。

说一下各种码的概念吧。

原码:一个整数,按照绝对值的大小转换成二进制数,最高位为符号位。

反码:将原码除最高位(符号位)外,其余各位按位取反,所得到的二进制码。正数的反码为原码。

补码:反码最低位加1即为补码。

关于负数的补码求法说明一下,先得到其反码,之后将反码加1即可。有些大神根据其原码,闭眼即得,这种能力需要修炼一下啊。

这时有些人可能会说,为什么要引入补码的形式呢?直接按照原码存储不就省事很多吗?嘿嘿,要记住,有些事情并不是你想省事就能省事的。好了来欣赏一下补码的优势吧。

计算机的带符号数用补码表示的优点:

  • 1负数的补码与对应正数的补码之间的转换可以用同一种方法-求补运算完成,可以简化硬件。
  • 2 可将减法变为加法,这样减法就可以用加法器进行计算了。
  • 3 两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位被舍弃。

心算求补(大神求补算法):

从最低位开始至找到的第一个1均不变,符号位不变,这之间的各位“求反”(0变1;1变0)。

原码:1010 1001  补码:1101 0111.

5.有符号数与无符号数的相互转换

无符号整数和有符号整数之间进行强制类型转换时,位模式不改变。

有符号数转换为无符号数时,负数转换为大的正数,相当于在原值上加上2的n次方,而正数保持不变。

无符号数转换为有符号数时,对于小的数将保持原值,对于大的数将转换为负数,相当于原值减去2的n次方。

当表达式中存在有符号数和无符号数类型时,所有的操作都自动转换为无符号类型。可见无符号数的运算优先级高于有符号数。

unsigned int a = 20;
signed int b = -130;

运算一下结果是 b>a 。

无符号int与有符号int比较大小,转化为无符号int来比较

int类型与非无符号int的类型比较时,非无符号int的类型转化为int来比较

无符号int类型与其他类型如unsigned short,signed short,unsigned char, char 比较时,其他类型一律转化为无符号int类型来比较

非无符号int类型和非int类型如unsigned short,signed short,unsigned char, char 比较时,一律转化为int类型来比较

6.转换大餐

有符号数的转换

原类型目标类型转换方法
 char

short

符号位扩展
charlong符号位扩展
charunsigned char最高符号位失去位意义,变为数据位
charunsigned short符号位扩展到short;然后从short转到unsigned short
charunsigned long符号位扩展到long;然后从long转换到unsigned long
charfloat符号位扩展到long;然后从long转到float
chardouble符号位扩展到long;然后从long转换到double
charlong double符号位扩展到long;然后从long转换到long double
shortchar保留低位字节
shortlong符号位扩展
shortunsigned char保留低位字节
shortunsigned short

最高为失去意义,变为数据位

shortunsigned long符号位扩展到long;然后从long转到unsigned long
shortfloat符号位扩展到long;然后从long转到float
shortdouble符号位扩展到long;然后从long转到double
shortlong double符号位扩展到long;然后从long转换到long double
longchar保留低位字节
longshort保留低位字节
longunsigned char保留低位字节
longunsigned short保留低位字节
longunsigned long最高为失去意义,变为数据位
longfloat使用单精度浮点数表示,可能失去精度
longdouble使用单精度浮点数表示,可能失去精度
longlong double使用单精度浮点数表示,可能失去精度

 

 

无符号数的转换

原类型目标类型转换方法
unsigned charchar最高为作符号位
unsigned charshort0扩展
unsigned charlong0扩展
unsigned charunsigned short0扩展
unsigned charunsigned long0扩展
unsigned charfloat转换到long;然后从long转换到float
unsigned chardouble转换到long;然后从long转换到double
unsigned charlong double转换到long;然后从long转换到long double
unsigned shortchar保留低位字节
unsigned shortshort最高为作符号位
unsigned shortlong0扩展
unsigned shortunsigned char保留低位字节
unsigned shortunsigned long0扩展
unsigned shortfloat转换到long;然后从long转换到float
unsigned shortdouble转换到long;然后从long转换到double
unsigned longlong double转换到long;然后从long转换到long double
unsigned longchar保留低位字节
unsigned longshort保留低位字节
unsigned longlong最高位作符号位
unsigned longunsigned char保留低位字节
unsigned longunsigned short保留低位字节
unsigned longfloat转换到long;然后从long转换到float
unsigned longdouble直接转换到double
unsigned longlong double转换到long;然后从long转换到long double

7.各种数据类型所占字节

32位平台下:

 ps:文中若有不当之处,请指出!

posted on 2015-01-12 16:31  RunningSnail 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/tgycoder/p/4218696.html

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值