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

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;
}

显示结果:

ui = 32768
si = -32768
ui = 16384
si = -16384
------------------------------
32768
-32768
49152
16384
------------------------------
32768
-32768
0
0
-------------------------------
32768
-32768
0
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 。

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 short 0扩展
unsigned char long 0扩展
unsigned char unsigned short 0扩展
unsigned char unsigned long 0扩展
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 long 0扩展
unsigned short unsigned char 保留低位字节
unsigned short unsigned long 0扩展
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:文中若有不当之处,请指出!

时间: 2024-10-11 16:14:01

关于有符号数和无符号数的转换的相关文章

关于有符号数和无符号数的转换 - C/C++

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

有符号数的加减法 和无符号数的加减法,和,系统是如何识别有符号数和无符号数的

一.有符号数的加减法 1.符号数与无符号数的人为规定性: 一个数,是有符号数还是无符号数都是人为规定的.进行二进制运算时用无符号数或是补码运算时,结果都是正确的. 10000100+00001110 若规定为无符号数,即 132+146=146D . 若规定为符号数,则为-124+14=-110,而[-110]补=10010010.解释:10000100是 -124的补码,0001110是14的补码,在机器中运算后得出的结果是[-110]的补码.机器中的有符号数的运算一般就是补码的运算. 2.补

有符号数和无符号数负数(转)

有符号数和无符号数负数 理解有符号数和无符号数负数在计算机中如何表示呢? 这一点,你可能听过两种不同的回答. 一种是教科书,它会告诉你:计算机用"补码"表示负数.可是有关"补码"的概念一说就得一节课,这一些我们需要在第6章中用一章的篇幅讲2进制的一切.再者,用"补码"表示负数,其实一种公式,公式的作用在于告诉你,想得问题的答案,应该如何计算.却并没有告诉你为什么用这个公式就可以和答案? 另一种是一些程序员告诉你的:用二进制数的最高位表示符号,最高

有符号数和无符号数

摘抄自:http://www.cnblogs.com/glacierh/archive/2013/07/16/3194658.html 1.      补码 在计算机中无符号数用原码表示,有符号数用补码表示.w位补码表示的值为: 最高位 也称符号位,1表示负数,0表示正数,符号位为0时,和无符号数的表示是相同的,以下是4位补码的示例: 0101 = -0*23 + 1*22 + 0*21 + 1*20 = 5 1101 = -1*23 + 1*22 + 0*21 + 1*20 = -3 w位的补

C语言之有符号数和无符号数

我们知道,在C语言中存在无符号数和有符号数(一些高级语言如Java里面是没有无符号数的),但是对于计算机而言,其本身并不区别有符号数和无符号数,因为在计算机里面都是0或者1,但是在我们的实际使用中有时候需要使用有符号数来表示一个整数,因此我们规定,当最高位为1的时,表示为负数,最高位为0时,表示为正数. 1:有符号数和无符号数在数值上的区别. 有符号数的最高位用来表示符号,所以在最大的数值上,有符号数的最大值小于无符号数.以一个字节为例: 有符号数的取值范围为:-128 - 0 - 127 无符

FPGA中的有符号数和无符号数的运算

在FPGA设计中,所有的算数运算符都是按照无符号数进行的.如果要完成有符号数计算,对于加.减操作通过补码处理即可用无符号加法完成.对于乘法操作,无符号数直接采用“*”运算符,有符号数运算可通过定义输出为 signed 来处理. 需要注意的是,尽量不要使有符号数与无符号数进行混合计算.因为只要有一个无符号数的运算单元,整个算式将被将成无符号数进行计算.   总之,正数和负数处理时都是按照补码的形式处理,具体究竟把这些补码理解为符号型还是无符号型,这就要看reg signed这样的声明了.如果声明了

C语言基础(5)-有符号数、无符号数、printf、大小端对齐

1.有符号数和无符号数 有符号数就是最高位为符号位,0代表正数,1代表负数 无符号数最高位不是符号位,而就是数的一部分而已. 1011 1111 0000 1111 1111 0000 1011 1010,如果当有符号数看待,那么他是一个负数的补码,如果当一个无符号数看待,他就是一个正数的原码 无符号数最小为0,不可能是负数 定义一个无符号的int unsigned int a; //使用unsigned int 定义了一个无符号的int变量,名字叫a short,long,long long,

C/C++ 有符号数和无符号数

在开始话题前,不妨先来看看以下这段代码 1 #include <iostream> 2 #include <stdio.h> 3 4 int main() { 5 int a = -1; 6 unsigned int b = 1; 7 std::cout << "a > b is " << (a > b) << std::endl; 8 std::cout << "a - b = "

注意sizeof()返回的数无符号数,有符号数遇到无符号数时变成无符号数

预测一下这道题的结果,注意unsigned与signed #include<iostream> #include<stdio.h> using namespace std; int arr[]={1,2,3,4,5}; int main(){ for(int i=-1;i<sizeof(arr)/sizeof(arr[0]) - 1;i++) cout<<arr[i+1]<<endl; } sizeof()返回的值是无符号数,有符号数遇到无符号数变成无