CSAPP第二章作业(部分)

2.58

首先要明确计算机存储数据的方式,无论在何种机器上都是按照地址由低到高进行存储,唯一的区别是小端机是先存低位大端机先存高位。例如数据0x11223344在小端机地址从低到高存储顺序是44 33 22 11,在大端机存储顺序为11 22 33 44。

在网上看了看,普遍说int类型占的字节数可能会随计算机和编译器的不同存在差异。所以这里使用一个int类型的1作为特殊值操作,无论在那种机器存储,这个int值的所有字节当中只会有一个0x01,如果这个1被存在地址最低的一个字节则说明是小端机,否则会存在地址最高的一个字节即大端机。所以这里只需要判断地址最低的一个字节是0x01还是0x00就可以确定大小端了。

这里直接取num(1)的地址,然后强制转换为char类型的指针,再将这个指针解引用即可得到最低字节。char类型在通常情况下均为1个字节

1 bool is_little_endian()
2 {
3     int num=1;
4     if( *((char*) &num)==1 )
5         return 1;
6     else
7         return 0;
8 }

 

2.71

xbyte这个函数要干的就是将一个32位unsigned类型(4个字节)当中的一个字节提取出来,然后把它符号拓展成单独的一个int类型。那么拓展的3个字节要填啥呢?根据符号拓展的规则,如果这一个字节是负数,则3个字节需要填充0xFF以保证拓展后仍然为负数,如果是正数则填充0x00保证拓展后仍然为正数,这就是符号拓展。

再看题里的代码,它首先把bytenum左移3位,这可以理解为bytenum*(2^3),然后再将word进行右移。这两步的意思就是将需要提取出来的字节右移至最低位,最后与0xFF也就是0x00 00 00 FF进行与运算,将3个高位字节全部设为0,只保留最低位字节,便达到了提取目标字节的目的。但是问题在于这里直接将3个高位字节设成0,而并不是根据字节正负来决定填充1还是0,所以这是无符号拓展并不是符号拓展,拓展出来的类型是unsigned而不是int。

在C语言当中右移>>为算术右移,也就是在右移是补0还是1取决于数的正负,也就是最高位符号位是0还是1。所以这里我们通过一次左移和一次右移实现符号拓展。首先将目标字节左移至最高位,这里通过一次减法和一次左移运算来得到需要左移的位数。左移完毕后目标字节已经位于最高位,因此这个时候直接算术右移24位即可,且右移操作会自动根据字节的正负在左边补0或1,右移结束后便得到了符号拓展的32位int

 

1 int xbyte(packed_t word, int bytenum)
2 {   
3     //将目标位左移至最高位
4     int k = word << ((3 - bytenum) << 3);
5     //再右移24位至最低位
6     return k>>24;
7 }

 

posted @ 2020-07-28 10:48  MisakaC  阅读(104)  评论(0)    收藏  举报