CSAPP(第二版) 第二章习题解答

CSAPP(第二版) 第二章习题解答

2.1 二进制《–》十六机制

A.将0x39A7F8转换为二进制

0x39A7F8

0011 1001 1010 0111 1111 1000

B. 二进制1100 1001 0111 1011转换为十六进制

A 9 7 B

C. 将0xD5E4C转换为二进制

1101 0101 1110 0100 1100

D. 将二进制10 0110 1110 0111 1011 0101转换为十六进制

补0: 0010 0110 1110 0111 1011 0101

转:2 6 E 7 B 5

2.2 二进制/十六进制表示

n 2 n 2^n 2n(十进制) 2 n 2^{n} 2n(十六进制)
9 512 0x200
19 1028*512 = 524288 0x80000
14 16384 0x4000
16 QwQ,不想算 0x10000
17 不想算 0x20000
5 32 0x20
7 128 0x80

方法: 当二进制表示为 2 n 2^n 2n次方时,十六进制如果可以写为 i + 4 j i+4j i+4j,则十六进制可以写为 0 x 2 i ( 0..0 ⏟ j 个 0 ) 0x2^i(\underbrace{0..0}_{j个0}) 0x2i(j0 0..0)

2 9 2^9 29为例子, 9 = 2 × 4 + 1 9 = 2\times 4+1 9=2×4+1,则可以表示为 0 x 200 0x200 0x200

2.3 O ⇔ \Leftrightarrow B ⇔ \Leftrightarrow H

十进制 二进制 十六进制
0 0000 0000 0x00
167 1100111 0x67
62 111100 0x3C
188 1111100 0x7C
55 0011 0111 0x37
136 1000 1000 0x88
243 1111 0011 0xF3
82 0101 0010 0x52
172 1010 1100 0xAC
251 1110 0111 0xE7

2.4 H 加法

Tip: 将十进制加减法规则应用于16进制,仅需将基数改为16,加减法时也需要注意满为16

0 x 503 c + 0 x 8 = 0 x 5044 0 x 503 c − 0 x 40 = 4 f f c 0 x 503 c + 64 = 0 x 505 c 0 x 50 e a − 0 x 503 c = 0 x a d \begin{aligned}0x503c + 0x8 &= 0x5044 \\0x503c - 0x40 &= 4ffc\\0x503c + 64 &= 0x505c\\0x50ea - 0x503c &= 0xad\end{aligned} 0x503c+0x80x503c0x400x503c+640x50ea0x503c=0x5044=4ffc=0x505c=0xad

2.5 大端序/小端序 — 对十六进制的word size输出

<1> prepare_way

typedef unsigned char* pointer_char;
void show_bytes(pointer_char x, int len){
  for(int i=0; i<len; ++i){
    printf("%.2x", x[i]);
  }
}

<2> 大端序/小端序

目前的big-endian 只存在sun系统及互联网协议中,因此在socket通信中需要将big-endian–>little endian来通信

题目要求的是输出三次递增1 2 3位的字长,则有:

Big-Endian Little-Endian
65 21
65 43 21 43
65 43 21 21 43 65

2.6 十六进制移位置匹配

因为机器不是sun的及浮点还没学,就不误导大家了qwq

2.7 char型调用

show_bytes函数与2.5相同

输出结果为:

"abcdefg"
 61 62 63 64 65 66 67

知:a~z的ascii码为0x61~0x7A

Imp: ascii字符码在任何系统上的结果都是一样的,与word size||字节大小规则无关

2.8 Bool Algebra运算

运算 结果
a [01101001]
b [01010101]
~a [10010110]
~b [10101010]
a&b [01000001]
a|b [01111101]
a^b [00111100]

可能疑惑: 将逻辑运算视为set运算,关于**^逻辑表示为异或**(对称求解)

2.9 Log.补的运算

位向量(集合)间补的运算即为求反~[vec]

R G B 颜色 R G B 颜色
0 0 0 黑色 1 0 0 红色
0 0 1 蓝色 1 0 1 红紫色
0 1 0 绿色 1 1 0 黄色
0 1 1 蓝绿色 1 1 1 白色

<1> 求八种颜色的补

求对应向量的反码后,根据表找到对应的补即可

<2> 颜色运用布尔运算的结果

根据上述2.8的规则求也成了(我是懒doge)

2.10 异或的妙用

数电里也提到过,0 ^ […] = […], 1 ^ […] = ~[…]

根据程序:

void replace(int *x, int *y){
	*y = *x^*y;
  *x = *x^*y;
  *y = *x^*y;
}

得:

Step *x *y
Initial a b
Step 1 a a^b
Step 2 a(ab) = 0^b=b a^b
Step 3 b b(ba) = 0^a = a

2.11 数组颠倒

题目太长,我选择不抄(懒doge again

  • A. First = [ 2 k + 1 2 \frac{2k+1}{2} 22k+1]+1, last. = [ 2 k + 1 2 \frac{2k+1}{2} 22k+1-1]
  • B. 可以视为当数组指针到中位数(数组位置)时(aa=0)–>(0a=a)–>(a^a=0)这三个步骤
  • C. 改为first

2.12 字节输出程序(little-debian)

Requests:

  • 除了x的最低有效字节,其他都需要全为0;
  • 最低有效字节不变,其他的位取补
  • 最低有效字节设置为1,其他字节保持不变

一开始的做法错了,想用字节数组输出,但是这个好傻qwq,并且我没实现orz

然后再看一遍题目,随机玩了玩移位,才感觉到这道题需要用的是逻辑运算

		int num = 0x87654321;
    /*A*/
    printf("%.8x\n", num&(0xFF));
    /*B*/
    printf("%.8x\n", num^(0x11111100));
    /*C*/
    printf("%.8x\n", num|(0x000000FF));

根据逻辑运算就可以得出啦

2.13 bis/bic 实现

要求: 只能用逻辑运算,理解一下即bis把m为1的位置,z对应的位也设为1;bic则把m为1的位置,z设为0.最后用bis和bic实现|及^运算

int bis(int x, int m){
    return x|m;
}

int bic(int x, int m){
    return x&(~m);
}
/*calculation of '|'*/
int bool_or(int x, int y){
    return bis(x, y);
}

/*calculation of '^'*/
int bool_xor(int x, int y){
    return bis(bic(x,y),bic(y,x));
}

**问题:**在一开始实现异或时没有考虑 x = 0 , m = 1 x=0,m=1 x=0,m=1的情况,如果只用bic来实现的话输出的仅为0,但实际应该是1

2.14 十六进制的运算

注意这里如果笔算,建议先将16进制转为二进制,进行集合的运算后能更快得到结果

表达式
x & y 0x20
x | y 0x7F
~x | ~y 0xDF
x & !y 0x00
x && y 0x01
x || y 0x01
!x || !y 0x00
x && ~y 0x01

对应程序:

		int x = 0x66, y = 0x39;
    printf("x&y = %x\n", x&y);
    printf("x|y = %x\n", x|y);
    printf("~x|~y = %x\n", ~x|~y);
    printf("x&!y = %x\n", x&!y);
    printf("x&&y = %x\n", x&&y);
    printf("x||y = %x\n", x||y);
    printf("!x||!y = %x\n", !x||!y);
    printf("x&&~y=%x\n", x&&~y);

突然发现练习题后面有答案qwq…

你可能感兴趣的:(计算机系统,c语言)