csapp2.2整数表示-创新互联
整形数据类型
网站栏目:csapp2.2整数表示-创新互联
标题来源:http://pwwzsj.com/article/jepio.html
- C语言支持多种数据类型用于表示有限范围的整数
其中各类型的特点是取值范围不对称,负数的范围比整数的范围大1 - C语言标准定义了每种数据类型能够表示的最小的取值范围
其中除了固定大小的的数据类型外,它们要求正数和负数的取值范围是对称的,固定大小的数据类型与2-9一致,包括正数与负数的不对称性。
- 设2进制整数有w位,便可用函数B2U表示
例如
该函数可将一个长度为w的位向量映射为0 ~ 2w-1之间的一个唯一值,
同时在0~ 2w-1之间的任何一个整数都可以映射为一个唯一的长度为w的位模式。
- 最常见的有符号数的表示方式是补码编码,其中单个字的有效最高位被定义为负权
当最高位为1,该数为-2w-1+其他位的数。例如 - 因此,w位的补码能表示的最小值为-2w-1大值为2w-1-1,
- 以下是针对不同字长,几个重要数字的位模式和数值
其中有几点值得注意,
第一,TMin并没有与之对应的正数,|TMin|=|TMax|+1,这是因为在补码中,一半的位模式表示负数,另一半的位模式表示非负数(0和正整数)
第二,大的无符号数值刚好比大的补码的两倍大1,补码表示中所有的负数在无符号表示中都变为了正数, - 为了更好理解,有如下代码
#include#include "headfile.h"
int main (){short x = 12345;
short mx = -x;
show_bytes((byte_pointer)&x, sizeof(short));
show_bytes((byte_pointer)&mx, sizeof(short));
return 0;
}
有符号数和无符号数之间的转换- 有如下代码
#includeint main(){short int v=-12345;
unsigned short uv=(unsigned)v;
printf("v=%d,uv=%u\n",v,uv);
return 0;
}
该代码输出结果为v=-12345,uv=53191
由此可见,强制类型转换不会改变原数的位值,只是改变了解释这些位的方式。
- 补码转换为无符号数
在补码的值上加上最高位,如下 - 无符号数转换为补码,同理
- 下图可以更直观的表示这两种转换
- C语言支持所有整数类型的无符号和有符号数的运算
- 导致类型转换发生的几种情况
- 显式强制类型转换
int tx, ty; unsigned ux, uy; tx = (int)ux; uy = (unsigned)ty;
- 一种类型的表达式被赋值给另外一种类型的变量时
int tx,ty; unsigned int ux,uy; tx=ux;//cast to signed uy=ty;//cast to unsigned
- 当用 printf进行格式化输出时
当其在32位机器上运行时,输出为int x=-1; unsigned u=2147483648; printf("x = %u = %d\n",x); printf("u = %u = %d\n",u);
x = 4294967295 = -1
u = 2147483648 = -2147483648- 当执行一个运算时,如果它的一个运算数是有符号的而另一个运算时是无符号的时,那么C语言会将这两个数都隐式地转换为无符号数,并假设这两个数都是非负。
这种运算对于像<和>这样的运算来说,会导致非直观的结果。
例如(-1<0u) =0
- 无符号数的零扩展
将一个无符号数转换为更大的数据类型时,只需在多出来的高位全部补0 - 补码数的符号扩展
当该补码数为正时,在多出的高位上补0
当该补码数为负时,在多出的高位上补1
例如:
short sx = -12345; //补码数的符号扩展
unsigned short usx = sx;
int x = sx;
unsigned ux = usx;
printf("sx = %d:\t", sx);
show_bytes((byte_pointer)&sx, sizeof(short));
printf("usx = %u:\t", usx);
show_bytes((byte_pointer)&usx, sizeof(short));
printf("x = %d:\t", x);
show_bytes((byte_pointer)&x, sizeof(short));
printf("ux = %u:\t", ux);
show_bytes((byte_pointer)&ux, sizeof(short));
这段代码打印如下输出
sx = -12345: c7cf
usx = 53191: c7cf
x = -12345: ffffc7cf
ux = 53191: 0000c7cf
- 从一个数据大小到另一个数据大小的转换,以及无符号和有符号数字之间的转换的相对顺序能够影响一个程序的行为。例如下面这段代码:
unsigned uy = sx; //数据类型转换的顺序对程序的影响
printf("uy = %u:\t", uy);
show_bytes((byte_pointer)&uy, sizeof(unsigned));
其输出为
uy = 4294954951: c7cfffff
这表明在将short转换为unsigned时,我们要先改变大小,之后再完成从有符号到无符号的转换,即(unsigned)sx等价于(unsigned)(int)sx。
同样的
int func1(unsigned word) //练习题2.23
{return (int)((word<< 48) >>248);
}
int func2(unsigned word)
{return ((int)word<< 48) >>48;
}
unsigned w = 0x87654321;
printf("%d\n", func1(w));
printf("%d\n", func2(w));
这段代码的输出为
67
17185
- 如这段代码所示
int x = 53191;
short sx = (short)x;
int y = sx;
当我们把x强制类型转换为short时,我们就将32位的int截断为了16位的short int。此时这个16位的位模式就是-12345的补码表示。当我们把它强制类型转换回int时符号扩展把高16位设置为1,从而生成-12345的32位补码表示。
(先缩小(溢出),后补位)
- 当我们截断一个数字时可能会改变它的值,这也是溢出的一种形式。
- 就像我们看到的那样,有符号数到无符号数的隐式强制类型转换导致了某些非直观的行为。而这些非直观的特性经常导致程序错误。并且这种包含了隐式强制类型转换的细微差别的错误很难被发现。
例如下面这段代码
float sum_elements(float a[],unsigned length){int i;
float result=0;
for (i = 0; i<= length-1; i++)
{result+=a[i];
}
return result;
}
其中当参数length为0时,会导致for中length-1为4294967295,而a[]并没有这么多位,因此导致内存错误。
又如下
当两字符串长度之差大于int可表示的大正数时,返回值发生溢出变为负值,此时函数运算的结果是错误的,而将该函数定义为unsigned int的话,便可以规避掉这一问题。
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
网站栏目:csapp2.2整数表示-创新互联
标题来源:http://pwwzsj.com/article/jepio.html