(CSAPP第三版系列)导航篇传送门
2.56 用不同的示例值运行show_bytes的代码。
#include
typedef unsigned char *byte_pointer;
void show_bytes(byte_pointer start, size_t len)
{
size_t i;
for(i = 0;i < len;i++)
printf("%.2x",start[i]);
printf("\n");
}
void show_int(int x)
{
show_bytes((byte_pointer)&x,sizeof(int));
}
void show_float(float x)
{
show_bytes((byte_pointer)&x,sizeof(float));
}
void show_pointer(void *x)
{
show_bytes((byte_pointer)&x,sizeof(void *));
}
int main()
{
int x = 15213;
float y = 152.13;
void *z = (void *)&x;
show_int(x);
show_float(y);
show_pointer(z);
return 0;
}
/*测试结果:
6d3b0000 //show_int(15213);
48211843 //show_float(152.13);
04ff6100 //show_pointer((void *)&x);
*/
2.60 写出该C函数代码unsignedreplace_byte(unsigned x,int I,unsigned char b)。
//由题意及x86-64为小端法机器编写程序
#include
typedef unsigned char *byte_pointer;
unsigned replace_byte(unsigned x,int i,unsigned char b);
int main()
{
for(int i = 0;i < sizeof(unsigned);i++)
printf("%x\n",replace_byte(0x12345678,i,0xab));
return 0;
}
unsigned replace_byte(unsigned x,int i,unsigned char b)
{
byte_pointer pt = (byte_pointer)&x; //pt保存x地址
*(pt + i) = b; //x的i字节替换成字节b
unsigned y = *((unsigned *)pt); //pt指向的unsigned数字
return y;
}
/*测试结果:
123456ab //replace_byte(0x12345678,0,0xab);
1234ab78 //replace_byte(0x12345678,1,0xab);
12ab5678 //replace_byte(0x12345678,2,0xab);
ab345678 //replace_byte(0x12345678,3,0xab);
*/
2.64写出代码实现该函数 int any_odd_one(unsigned x)
#include
int any_odd_one(unsigned x)
{
return 0 != (x&0xaaaaaaaa);
}
int main()
{
printf("%d\n",any_odd_one(0x5)); //二进制表示 00000000 00000000 00000000 00000101
printf("%d\n",any_odd_one(0x25));//二进制表示 00000000 00000000 00000000 00100101
printf("%d\n",any_odd_one(0x7)); //二进制表示 00000000 00000000 00000000 00001101
return 0;
}
/*测试结果
0
1
1
*/
2.68 写出具有如下原型的函数的代码:int lower_one_mask(intn);
#include
#include
int lower_one_mask(int n)
{
unsigned x = ((INT_MAX)<<1) + 1u; //x位模式:1111111111111111...
return (int)(x>>((sizeof(int)<<3)-n)); //对x移位实现函数的功能
}
int main()
{
for(int i = 1;i <= sizeof(int)<<3;i++)
printf("%x\n",lower_one_mask(i));
return 0;
}
/*测试结果:
1 //lower_one_mask(1)
3 //lower_one_mask(2)
7 //lower_one_mask(3)
f //lower_one_mask(4)
1f //lower_one_mask(5)
3f //lower_one_mask(6)
7f //lower_one_mask(7)
ff //lower_one_mask(8)
…
3fffffff //lower_one((sizeof(int)<<3)-2);
7fffffff //lower_one((sizeof(int)<<3)-1);
ffffffff //lower_one(sizeof(int)<<3);
*/
2.72 voidcopy_int(int val,void *buf,int maxbytes);
A. 解释为什么代码中的条件测试总是成功。
sizeof(val)结果类型为size_t,在maxbytes-sizeof(val)时按无符号数进行运算,
则运算结果仍然为无符号数,所以if条件"maxbytes-sizeof(val)>=0"恒成立。
B. 如何重写这个条件测试,使之工作正确。
void copy_int(int val,void *buf,int maxbytes)
{
if(maxbytes >= (int)sizeof(val))
memcpy(buf,(void *)&val,sizeof(val));
}
2.76 编写calloc的实现,通过调用malloc执行分配,调用memset将内存设置为0。
#include
#include
void *calloc(size_t nmemb,size_t size)
{
if(nmemb == 0 || size == 0)
return NULL;
else
{
/*使用cnt作为malloc(),memset()函数的参数,避免由算数溢出引起的漏洞。*/
size_t cnt = nmemb * size;
pt = (void *)malloc(cnt);
if(pt != NULL)
memset(pt,0,cnt);
return pt;
}
}
2.80 写出函数threefourths的代码。
#include
int threefourths(int x)
{
/*基本思路:3/4x=1/4x+1/2x。对于舍入误差来说,只与
符号位和最低两位有关。据此编写程序。*/
int a = x>>((sizeof(int)<<3)-1);
int b = x & 1;
int c = (x & 3 - b)>>1;
int diff = b + c;
int mis = !a && !(b==0&&c==0);
return (x>>2)+(x>>1)+diff-mis;
}
int main() //测试程序
{
printf("i threefourths(i) 3*4/i\n");
for(int i = -8;i <= 8;i++)
printf("%2d %12d %12d\n",i,threefourths(i),3*i/4);
return 0;
}
/*测试结果:
i threefourths(i) 3*4/i
-8 -6 -6
-7 -5 -5
-6 -4 -4
-5 -3 -3
-4 -3 -3
-3 -2 -2
-2 -1 -1
-1 0 0
0 0 0
1 0 0
2 1 1
3 2 2
4 3 3
5 3 3
6 4 4
7 5 5
8 6 6
*/
2.84 填写程序的返回值。
int float_le(float x,float y)
{
unsigned ux = f2u(x);
unsigned uy = f2u(y);
/*Get the sign bits*/
unsigned sx = ux >> 31;
unsigned sy = uy >> 31;
/*Give an expression using only ux,uy,sx,and sy*/
return ((sx&&sy)&&(ux>=uy))||((!sx&&!sy)&&(ux<=uy))||(sx&&!sy); //三种可能情况
}
2.88
2.92 实现该函数 float_bits float_negate(float_bitsf);
typedef unsigned float_bits
float_bits float_negate(float_bits f)
{
unsigned sign = f >> 31;
unsigned exp = f >> 23 & 0xff;
unsigned frac = f & 0x7fffff;
if(exp == 0xff && frac)
return f;
else
return (exp << 23)|frac;
}
2.96 实现该函数 int float_f2i(float_bits f);
int float_f2i(float_bits f)
{
unsigned sign = f>>31;
unsigned exp = (f>>23) & 0xFF;
unsigned frac = f & 0x7FFFFF;
if (exp > 158) //超出表示范围
return (int) 0x80000000u;
if (exp <= 126) //非规格化数处理
return (int) 0;
/*由IEEE 754编码规则,编写程序*/
unsigned val = (0x80000000u | (frac << 8))>>(158-exp);
/*下面考虑是否超出表示范围*/
if (!sign)
return val > 0x7FFFFFFF ? 0x80000000u : val;
else
return val > 0x80000000u ? 0x80000000u : -val;
}