CSAPP第二章家庭作业参考答案

(CSAPP第三版系列)导航篇传送门


2.56 用不同的示例值运行show_bytes的代码。

#include <stdio.h>

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 <stdio.h>

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 <stdio.h>

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 <stdio.h>
#include <limits.h>

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 <stdlib.h>
#include <string.h>

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 <stdio.h>

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

猜你喜欢

转载自blog.csdn.net/qq512028505/article/details/79127219