csapp2.2 整数表示

整形数据类型

  • 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 <stdio.h>
#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;
}

有符号数和无符号数之间的转换

  • 有如下代码
#include <stdio.h>
int 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语言中的有符号数和无符号数

  • 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进行格式化输出时
    int x=-1;
    unsigned u=2147483648;
    
    printf("x = %u = %d\n",x);
    printf("u = %u = %d\n",u);
    
    当其在32位机器上运行时,输出为
    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的话,便可以规避掉这一问题。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值