关于有符号数和⽆符号数的转换
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);
return0;
}
显⽰结果:
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符号位扩展
char long符号位扩展
char unsigned char最⾼符号位失去位意义,变为数据位
char unsigned short符号位扩展到short;然后从short转到unsigned short
char unsigned long符号位扩展到long;然后从long转换到unsigned long
char float符号位扩展到long;然后从long转到float
char double符号位扩展到long;然后从long转换到double
char long double符号位扩展到long;然后从long转换到long double
short char保留低位字节
short long符号位扩展
short unsigned char保留低位字节
short unsigned short最⾼为失去意义,变为数据位
short unsigned long符号位扩展到long;然后从long转到unsigned long
short float符号位扩展到long;然后从long转到float
short double符号位扩展到long;然后从long转到double
short long double符号位扩展到long;然后从long转换到long double
long char保留低位字节
long short保留低位字节
long unsigned char保留低位字节
long unsigned short保留低位字节
long unsigned long最⾼为失去意义,变为数据位
long float使⽤单精度浮点数表⽰,可能失去精度
long double使⽤单精度浮点数表⽰,可能失去精度
long long double使⽤单精度浮点数表⽰,可能失去精度
⽆符号数的转换
原类型⽬标类型转换⽅法unsigned char char最⾼为作符号位
unsigned char short0扩展
unsigned char long0扩展
unsigned char unsigned short0扩展
unsigned char unsigned long0扩展
unsigned char float转换到long;然后从long转换到float
unsigned char double转换到long;然后从long转换到double unsigned char long double转换到long;然后从long转换到long double unsigned short char保留低位字节
unsigned short short最⾼为作符号位
unsigned short long0扩展
unsigned short unsigned char保留低位字节
unsigned short unsigned long0扩展
unsigned short float转换到long;然后从long转换到float
unsigned short double转换到long;然后从long转换到double unsigned long long double转换到long;然后从long转换到long double unsigned long char保留低位字节
unsigned long short保留低位字节
unsigned long long最⾼位作符号位
unsigned long unsigned char保留低位字节
unsigned long unsigned short保留低位字节
unsigned long float转换到long;然后从long转换到float
unsigned long double直接转换到double
unsigned long long double转换到long;然后从long转换到long double 7.各种数据类型所占字节
32位平台下:
ps:⽂中若有不当之处,请指出!