CSAPP第二章家庭作业

第二章 信息的表示和处理

2-55 ~ 2-57

头文件show_bytes.c

1
2
3
4
5
6
7
8
9
10
11
#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");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#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_short(short x){
show_bytes((byte_pointer) &x, sizeof(short));
}

void show_long(long x){
show_bytes((byte_pointer) &x, sizeof(long));
}

void show_double(double x){
show_bytes((byte_pointer) &x, sizeof(double));
}

void show_pointer(void *x){
show_bytes((byte_pointer) &x, sizeof(void *));
}


// test
void test_show_bytes(int val){
int ival = val;
short sval = (short) ival;
long lval = (long) ival;
double dval = (double) ival;
int *pval = &ival;

show_int(ival);
show_short(sval);
show_long(lval);
show_double(dval);
show_pointer(pval);
}

//main
int main(){
test_show_bytes(12345);
}

show_bytes打印出每个以十六进制表示的字节。

上面程序使用强制类型转换来访问和打印不同程序对象的字节表示。

我们将byte_pointer定义为一个指向类型为unsigned char的对象指针,这样一个字节指针引用一个字节序列,其中每个字节都被认为是一个非负整数。该字节数指定为数据类型size_t,表示数据结构大小的首选数据类型。

c格式化指针 "%.2x"表明整数必须用至少两个数字的十六进制格式输出

sizeof(T)返回存储一个类型为T的对象所需要的字节数。需要注意的是sizeof不是一个固定的值,在不同机器上可能会不同

输出十六进制:

39300000 3930 3930000000000000 00000000801cc840 e8c779b7f77f0000

2-58

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>

typedef unsigned char* byte_pointer;

int is_litter_endian(){
int test = 0x01;
byte_pointer p = (byte_pointer) & test;
if(*p)
return 1;
else
return 0;
}

int main(){
return is_litter_endian();
}

编译运行

1
gcc 2_58.c && ./a.out ; echo $?

输出

1

2-59

很明显我们只需要

ox89ABCDEF & 0xFF = 0x000000EF

0x76543210 & ~0xFF = 0x76543200

最后

0x000000EF | 0x76543200 = 0x765432EF

1
2
3
4
5
6
7
#include <stdio.h>

int main(){
int x = 0x89ABCDEF;
int y = 0x76543210;
printf("0x%.8x\n", (x & 0xff) | (y & ~0xff));
}

编译运行

1
gcc 2_59.c && ./a.out

输出

0x765432ef

2-60

为了使replace_byte(0x12345678, 2, 0xAB) --> 0x12AB5678

我们先算出左移的位,也就是move = 2 * 8 = 16

x & ~(0xff << move) = 0x12005678

b << move = 0xAB0000

0x12005678 | 0xAB0000 = 0x12AB5678

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>

unsigned replace_byte(unsigned x, int i, unsigned char b){
int move = i * 8;
return x & ~(0xff << move) | b << move;
}

int main(){
printf("%.8x\n", replace_byte(0x12345678, 2, 0xAB));
printf("%.8x\n", replace_byte(0x12345678, 0, 0xAB));
}

编译运行

1
gcc 2_60.c && ./a.out

输出

0x12AB5678

0x123456AB

2-61

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>

int main(){
int x;

/* A: Any bit x is equal to 1 */
x = 0xffffff00;
printf("%d\n", !~x);

/* B: Any bit x is equal to 0 */
x = 0x000000ff;
printf("%d\n", !x);

/* C: The bits in the least significant byte of x are equal to 1 */
x = 0xffffff00;
printf("%d\n", !~(x | ~0xff));

/* D: The bits in the highest significant byte of x are equal to 0*/
x = 0x00ffffff;
printf("%d\n",!((x >> ((sizeof(int)-1) << 3)) & 0xff));
}

编译运行

1
gcc 2_61.c && ./a.out

输出:

0

0

0

1

2-62

码制 添补代码
正数 源码,补码,反码 0
负数 源码 0
补码 左移补0
右移补1
反码 1

所以这里我们只需要判断(-1 >> 1) == -1即可,因为-1的补码为11,右移一位后也是11

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>

int int_shift_are_arithmetic(){
int test = -1;
return (test >> 1) == -1;
}

int main(){
int_shift_are_arithmetic();
}

编译运行

1
gcc 2_58.c && ./a.out ; echo $?

输出:

0

2-63

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>

unsigned srl(unsigned x, int k){
/* Perform shift arithmetically */
unsigned xsra = (int) x >> k;
int w = sizeof(int) * 8;
unsigned z = 2 << (w - k - 1);
return (z - 1) & xsra;
}

int sra(int x, int k){
/* Perform shift logically */
int xsrl = (unsigned) x >> k;
int w = sizeof(int) * 8;
unsigned z = 1 << (w - k - 1);
unsigned mask = z - 1;
unsigned right = mask & xsrl;
unsigned left = ~mask & (~(z & xsrl) + z);
return left | right;
}

void test(){
printf("%x\n", srl(8, 2));
printf("%x\n", sra(8, 2));
printf("%x\n", sra(-8, 2));
}

int main(){
test();
}

2-64

如果奇位都为1,则返会1,否则返回0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>

/*
Return 1 when any odd bit of x equals 1; 0 otherwise.
Assume w = 32
*/

int any_odd_one(unsigned x){
// A = 1010,刚好偶数都为1
int mask = 0xAAAAAAAA;
return 0 != (x & mask);
}

int main(){
int test1 = 0x5; // 00000000 00000000 00000000 00000101
int test2 = 0x7; // 00000000 00000000 00000000 00000111
printf("%d\n", any_odd_one(test1));
printf("%d\n", any_odd_one(test2));
}

编译运行

1
gcc 2_64.c && ./a.out

输出:

0

1