初始完成日期:2017.9.26

许可:除2.55对应代码外(如需使用请联系 randy.bryant@cs.cmu.edu),任何人可以自由的使用,修改,分发本文档的代码。

本机环境: (有一些需要在多种机器上测试的就没有试验)

  1. frank@under:~/tmp$ uname -a
  2. Linux under 4.10.0-35-generic #39~16.04.1-Ubuntu SMP Wed Sep 13 09:02:42 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

2.55

  1. /*这一段代码的大部分来自http://csapp.cs.cmu.edu/3e/students.html*/
  2. /* $begin show-bytes */
  3. #include <stdio.h>
  4. /* $end show-bytes */
  5. #include <stdlib.h>
  6. #include <string.h>
  7. /* $begin show-bytes */
  8. typedef unsigned char *byte_pointer;
  9. void show_bytes(byte_pointer start, size_t len) {
  10. size_t i;
  11. for (i = 0; i < len; i++)
  12. printf(" %.2x", start[i]); //line:data:show_bytes_printf
  13. printf("\n");
  14. }
  15. void show_int(int x) {
  16. show_bytes((byte_pointer) &x, sizeof(int)); //line:data:show_bytes_amp1
  17. }
  18. void show_float(float x) {
  19. show_bytes((byte_pointer) &x, sizeof(float)); //line:data:show_bytes_amp2
  20. }
  21. void show_pointer(void *x) {
  22. show_bytes((byte_pointer) &x, sizeof(void *)); //line:data:show_bytes_amp3
  23. }
  24. /* $end show-bytes */
  25. /* $begin test-show-bytes */
  26. void test_show_bytes(int val) {
  27. int ival = val;
  28. float fval = (float) ival;
  29. int *pval = &ival;
  30. show_int(ival);
  31. show_float(fval);
  32. show_pointer(pval);
  33. }
  34. /* $end test-show-bytes */
  35. void simple_show_a() {
  36. /* $begin simple-show-a */
  37. int val = 0x87654321;
  38. byte_pointer valp = (byte_pointer) &val;
  39. show_bytes(valp, 1); /* A. */
  40. show_bytes(valp, 2); /* B. */
  41. show_bytes(valp, 3); /* C. */
  42. /* $end simple-show-a */
  43. }
  44. void simple_show_b() {
  45. /* $begin simple-show-b */
  46. int val = 0x12345678;
  47. byte_pointer valp = (byte_pointer) &val;
  48. show_bytes(valp, 1); /* A. */
  49. show_bytes(valp, 2); /* B. */
  50. show_bytes(valp, 3); /* C. */
  51. /* $end simple-show-b */
  52. }
  53. void float_eg() {
  54. int x = 3490593;
  55. float f = (float) x;
  56. printf("For x = %d\n", x);
  57. show_int(x);
  58. show_float(f);
  59. x = 3510593;
  60. f = (float) x;
  61. printf("For x = %d\n", x);
  62. show_int(x);
  63. show_float(f);
  64. }
  65. void string_ueg() {
  66. /* $begin show-ustring */
  67. const char *s = "ABCDEF";
  68. show_bytes((byte_pointer) s, strlen(s));
  69. /* $end show-ustring */
  70. }
  71. void string_leg() {
  72. /* $begin show-lstring */
  73. const char *s = "abcdef";
  74. show_bytes((byte_pointer) s, strlen(s));
  75. /* $end show-lstring */
  76. }
  77. void show_twocomp()
  78. {
  79. /* $begin show-twocomp */
  80. short x = 12345;
  81. short mx = -x;
  82. show_bytes((byte_pointer) &x, sizeof(short));
  83. show_bytes((byte_pointer) &mx, sizeof(short));
  84. /* $end show-twocomp */
  85. }
  86. int main(int argc, char *argv[])
  87. {
  88. int val = 12345;
  89. if (argc > 1) {
  90. if (argc > 1) {
  91. val = strtol(argv[1], NULL, 0);
  92. }
  93. printf("calling test_show_bytes\n");
  94. test_show_bytes(val);
  95. } else {
  96. printf("calling show_twocomp\n");
  97. show_twocomp();
  98. printf("Calling simple_show_a\n");
  99. simple_show_a();
  100. printf("Calling simple_show_b\n");
  101. simple_show_b();
  102. printf("Calling float_eg\n");
  103. float_eg();
  104. printf("Calling string_ueg\n");
  105. string_ueg();
  106. printf("Calling string_leg\n");
  107. string_leg();
  108. }
  109. return 0;
  110. }

编译运行输出:

  1. frank@under:~/tmp$ gcc 255.c && ./a.out
  2. calling show_twocomp
  3. 39 30
  4. c7 cf
  5. Calling simple_show_a
  6. 21
  7. 21 43
  8. 21 43 65
  9. Calling simple_show_b
  10. 78
  11. 78 56
  12. 78 56 34
  13. Calling float_eg
  14. For x = 3490593
  15. 21 43 35 00
  16. 84 0c 55 4a
  17. For x = 3510593
  18. 41 91 35 00
  19. 04 45 56 4a
  20. Calling string_ueg
  21. 41 42 43 44 45 46
  22. Calling string_leg
  23. 61 62 63 64 65 66

数据的低位放置在低地址处,字符串按照顺序从低位地址排列。由此可知该机器为小端字节排序。


2.56

show-bytes代码同2.55

  1. frank@under:~/tmp$ gcc 255.c && ./a.out 192837465
  2. calling test_show_bytes
  3. 59 77 7e 0b
  4. 76 e7 37 4d
  5. 28 00 4d 93 fc 7f 00 00

十进制192837465二进制表示为:1011011111100111011101011001。

  1. 十六进制表示为:0xB7E7759,所以第一行的数据表示这是小端字节排序。

  2. 将二进制小数点左移二十七位,由于单精度浮点数尾数部分只有23位(IEEE 756),多出来的4位1001将丢弃,由于默认的“round to even”,高位将进一位,即1.01101111110011101110110*2^27,bias = 2^7 - 1 = 127,所以阶码部分应为127+27=0x9A,整体为:0,10011010,01101111110011101110110即0x4D37E776。由此看出为小端字节排序。

  3. 该行为小端字节显示的指针。


2.57

  1. #include <stdio.h>
  2. typedef unsigned char *byte_pointer;
  3. void show_short(void);
  4. void show_long(void);
  5. void show_double(void);
  6. void show_bytes(byte_pointer start, size_t len);
  7. int main(int argc, char const *argv[])
  8. {
  9. show_short();
  10. show_long();
  11. show_double();
  12. return 0;
  13. }
  14. void show_bytes(byte_pointer start, size_t len) {
  15. size_t i;
  16. for (i = 0; i < len; i++)
  17. printf(" %.2x", start[i]);
  18. printf("\n");
  19. }
  20. void show_short(void)
  21. {
  22. short i = 12345;
  23. printf("short i = 12345\n");
  24. show_bytes((byte_pointer)&i, sizeof i);
  25. }
  26. void show_long(void)
  27. {
  28. long i = 123456789;
  29. printf("long i = 123456789\n");
  30. show_bytes((byte_pointer)&i, sizeof i);
  31. }
  32. void show_double(void)
  33. {
  34. double i = 123456789.0;
  35. printf("double i = 123456789.0\n");
  36. show_bytes((byte_pointer)&i, sizeof i);
  37. }

编译运行输出:

  1. frank@under:~/tmp$ ./a.out
  2. short i = 12345
  3. 39 30
  4. long i = 123456789
  5. 15 cd 5b 07 00 00 00 00
  6. double i = 123456789.0
  7. 00 00 00 54 34 6f 9d 41

2.58

  1. #include <stdio.h>
  2. #include <stdint.h>
  3. int is_little_endian(void);
  4. int main(int argc, char const *argv[])
  5. {
  6. return is_little_endian();
  7. }
  8. int is_little_endian(void)
  9. {
  10. int32_t i = 1;
  11. unsigned char *p = (unsigned char *)&i;
  12. if(*p)
  13. {
  14. return 1;
  15. }
  16. return 0;
  17. }

编译运行输出:

  1. frank@under:~/tmp$ gcc 258.c && ./a.out ; echo $?
  2. 1

2.59

  1. #include <stdio.h>
  2. int main(int argc, char const *argv[])
  3. {
  4. int x = 0x89ABCDEF;
  5. int y = 0x76543210;
  6. printf("0x%.8X\n", x&0xFF | y&~0xFF);
  7. return 0;
  8. }

编译运行输出:

  1. frank@under:~/tmp$ gcc 259.c && ./a.out
  2. 0x765432EF

2.60

  1. #include <stdio.h>
  2. unsigned replace_byte(unsigned x, int i, unsigned char b);
  3. int main(int argc, char const *argv[])
  4. {
  5. printf("%#.8x\n", replace_byte(0x12345678, 2, 0xAB));
  6. printf("%#.8x\n", replace_byte(0x12345678, 0, 0xAB));
  7. return 0;
  8. }
  9. unsigned replace_byte(unsigned x, int i, unsigned char b)
  10. {
  11. int move = i * 8;
  12. return x & ~(0xFF << move) | b << move;
  13. }

编译运行输出:

  1. frank@under:~/tmp$ gcc 260.c && ./a.out
  2. 0x12ab5678
  3. 0x123456ab

2.61

  1. #include <stdio.h>
  2. int main(int argc, char const *argv[])
  3. {
  4. int x, y; /* y means 0 should be returned */
  5. int sizeof_int = sizeof(int);
  6. /*condition A*/
  7. x = ~0;
  8. y = 0xFFFFFF00;
  9. printf("%d\t%d\n", !(~x), !(~y));
  10. /*condition B*/
  11. x = 0;
  12. y = 0x000000FF;
  13. printf("%d\t%d\n", !x, !y);
  14. /*condition C*/
  15. x = 0x000000FF;
  16. y = 0x0000000F;
  17. printf("%d\t%d\n", !((x ^ 0xFF)<<((sizeof_int-1)<<3)), !((y ^ 0xFF)<<((sizeof_int-1)<<3)));
  18. /*condition D*/
  19. x = 0x00FFFFFF;
  20. y = 0x0FFFFFFF;
  21. printf("%d\t%d\n", !(x >> ((sizeof_int-1) << 3)), !(y >> ((sizeof_int-1) << 3)));
  22. return 0;
  23. }

编译运行输出:

  1. frank@under:~/tmp$ gcc 261.c && ./a.out
  2. 1 0
  3. 1 0
  4. 1 0
  5. 1 0

2.62

  1. #include <stdio.h>
  2. int int_shifts_are_arithmetic(void);
  3. int int_shifts_are_logic(void);
  4. int main(int argc, char const *argv[])
  5. {
  6. printf("%d\n", int_shifts_are_arithmetic());
  7. printf("%d\n", int_shifts_are_logic());
  8. return 0;
  9. }
  10. int int_shifts_are_arithmetic(void)
  11. {
  12. int x = ~0;
  13. return x >> 1 == x;
  14. }
  15. int int_shifts_are_logic(void)
  16. {
  17. unsigned x = ~0;
  18. return x >> 1 == x;
  19. }

我这里由于没有不同字长/不同机器,就暂时用unsigned 代替了一下逻辑右移。

编译运行输出:

  1. frank@under:~/tmp$ ./a.out
  2. 1
  3. 0

2.63

  1. #include <stdio.h>
  2. unsigned srl(unsigned x, int k);
  3. int sra(int x, int k);
  4. int main(int argc, char const *argv[])
  5. {
  6. printf("%#.8x\n", srl(0x80000000, 8));
  7. printf("%#.8x\n", sra(0x80000000, 8));
  8. return 0;
  9. }
  10. unsigned srl(unsigned x, int k)
  11. {
  12. /* Perform shift arithmetically */
  13. unsigned xsra = (int) x >> k;
  14. /*思路是由k形成诸如0x00FFFFFF这样的掩码,与xsra进行与操作从而将高位置零*/
  15. unsigned w = sizeof(int) << 3;
  16. unsigned mask = ~(((1 << k)-1)<<(w-k));
  17. /*(1 << k)-1能够获得低位连续为1,高位为0的掩码,但是其不能达到全1,于是继续向左移w-k然后取反*/
  18. return mask & xsra;
  19. }
  20. int sra(int x, int k)
  21. {
  22. /* Perform shift logically */
  23. int xsrl = (unsigned) x >> k;
  24. /*这个题目的关键点是判断符号位是否为1,通过test &= xsrl,test为零如果符号位为0,否则test不变(处于符号位位置*/
  25. unsigned w = sizeof(int) << 3;
  26. int test = 1 << (w-1-k);
  27. test &= xsrl;
  28. int mask = ~(test - 1);
  29. /*test为零时,~(test - 1)为全零,不会改变xsrl*/
  30. return mask | xsrl;
  31. }

这个题目卡了一会,主要是不能用右移比较麻烦。

编译运行输出:

  1. frank@under:~/tmp$ gcc 263.c && ./a.out
  2. 0x00800000
  3. 0xff800000

2.64

  1. #include <stdio.h>
  2. int any_odd_one(unsigned x);
  3. int main(int argc, char const *argv[])
  4. {
  5. printf("%d\t%d\n", any_odd_one(1011), any_odd_one(1024));
  6. return 0;
  7. }
  8. int any_odd_one(unsigned x)
  9. {
  10. unsigned sizeof_unsigned = sizeof(unsigned);
  11. unsigned w = sizeof_unsigned << 3;
  12. return !!(x << (w-1));
  13. }

编译运行输出:

  1. frank@under:~/tmp$ gcc 264.c && ./a.out
  2. 1 0

2.65 (终于碰见个四星的。。。)

  1. /*二分法/加法无法达到要求
  2. 第一次尝试:
  3. int odd_ones(unsigned x);
  4. int main(int argc, char const *argv[])
  5. {
  6. int sizeof_int = sizeof(int);
  7. return 0;
  8. }
  9. int odd_ones(unsigned x)
  10. {
  11. int mask1 = 0x55555555;
  12. int mask2 = 0x33333333;
  13. int mask3 = 0x0F0F0F0F;
  14. int mask4 = 0x00FF00FF;
  15. int mask_odd_or_even = 1
  16. x = ((x >> 1)& mask1) + (x & mask1);
  17. x = ((x >> 2)& mask2) + (x & mask2);
  18. x = ((x >> 4)& mask3) + (x & mask3);
  19. x = ((x >> 8)& mask4) + (x & mask4);
  20. x = (x >> 16) + x;
  21. return x & mask_odd_or_even;
  22. }
  23. 第二次尝试:
  24. int odd_ones(unsigned x);
  25. int main(int argc, char const *argv[])
  26. {
  27. unsigned x1 = 0xFF00FF00;
  28. unsigned x2 = 0xFF01FF00;
  29. printf("%d\t%d\n", odd_ones(x2), odd_ones(x1));
  30. return 0;
  31. }
  32. int odd_ones(unsigned x)
  33. {
  34. int mask1 = 0x55555555;
  35. int mask2 = 0x33333333;
  36. int mask3 = 0x0F0F0F0F;
  37. int mask4 = 0x00FF00FF;
  38. int mask_odd_or_even = 1;
  39. x = ((x >> 1)& mask1) + (x & mask1);
  40. x = x & mask1;
  41. x = (x >> 16) + x;
  42. x = x & mask1;
  43. x = (x >> 8) + x;
  44. x = x & mask1;
  45. x = (x >> 4) + x;
  46. x = x & mask1;
  47. x = (x >> 2) + x;
  48. return x & mask_odd_or_even;
  49. }
  50. */
  51. //第三次尝试:使用二分法/异或
  52. #include <stdio.h>
  53. int odd_ones(unsigned x);
  54. int main(int argc, char const *argv[])
  55. {
  56. unsigned x1 = 0xFF00FF00;
  57. unsigned x2 = 0xFF01FF00;
  58. printf("%d\t%d\n", odd_ones(x2), odd_ones(x1));
  59. return 0;
  60. }
  61. int odd_ones(unsigned x)
  62. {
  63. x = x ^ (x >> 16);
  64. x = x ^ (x >> 8);
  65. x = x ^ (x >> 4);
  66. x = x ^ (x >> 2);
  67. x = x ^ (x >> 1);
  68. return x & 1;
  69. }

这个题的关键点在于如何表示偶数(将所有“1”相加末位为0)以及类似二分法的相加方法,同时注意到每次需要用用掩码将以前的高位置零。

这个题目是不会有“溢出”的情况的,因为1+1=10,10+10=0100,0100+0100=00001000......datalab实验里有一个相似的题目,那个题目更难一些。

以上想法在满足“Your code should contain a total of at most 12 arithmetic, bitwise, and logical

operations.”时出现了问题,根本原因在于二分法需要顾及到低位相加可能产生的进位,所以每次都需要用掩码将特定的高位置零,思路有点受到之前datalab实验的束缚(那个是要计算“1”的总数目)。这里计算的是“1”的数目的奇偶,不用考虑进位,异或运算是最佳选择,因为1+1和0+0均产生0(代表偶数),1+0和0+1均产生1(代表奇数)。

编译运行输出:

  1. frank@under:~/tmp$ gcc 265.c && ./a.out
  2. 1 0

2.66

  1. #include <stdio.h>
  2. #include <limits.h>
  3. /*
  4. * Generate mask indicating leftmost 1 in x. Assume w=32.
  5. * For example, 0xFF00 -> Ox8000, and Ox6600 --> Ox4000.
  6. * If x = 0, then return 0.
  7. */
  8. int leftmost_one(unsigned x);
  9. int main(int argc, char const *argv[])
  10. {
  11. printf("%#.8x\n", leftmost_one(0xFF00));
  12. printf("%#.8x\n", leftmost_one(0x6600));
  13. printf("%#.8x\n", leftmost_one(0x88886600));
  14. printf("%#.8x\n", leftmost_one(0));
  15. return 0;
  16. }
  17. int leftmost_one(unsigned x)
  18. {
  19. unsigned sizeof_unsigned = sizeof(unsigned);
  20. unsigned w = sizeof_unsigned << 3;
  21. x |= x >> 1;
  22. x |= x >> 2;
  23. x |= x >> 4;
  24. x |= x >> 8;
  25. x |= x >> 16;
  26. return x & ((~x >> 1)|INT_MIN);
  27. }
  28. /*
  29. * Your code should contain a total of at most 15 arithmetic, bitwise, and logical
  30. * operations.
  31. * Hint: First transform x into a bit vector of the form [O · · · 011 · . · 1].
  32. */

最后与INT_MIN做或运算是为了处理0x80000000这种边界情况,在这种情况下,~x >> 1由于没有更高位,而x又是unsigned类型,所以最高位会是0而非1,为了适应这种情况,强制将~x >> 1最高位置1。

编译运行输出:

  1. frank@under:~/tmp$ gcc 266.c && ./a.out
  2. 0x00008000
  3. 0x00004000
  4. 0x80000000
  5. 00000000

另外,Web Asides http://csapp.cs.cmu.edu/3e/waside/waside-tneg.pdf 上面有一个利用-x和x的区别在于除最右1之前位翻转的特性求rightmost_one: x&-x, 有时间可以看看。


2.67

A:

(C11, 6.5.7p3) "If the value of the right operand is negative or is greater than or equal to the width of the promoted left operand, the behavior is undefined"

B:

  1. #include <stdio.h>
  2. int int_size_is_32();
  3. int main(int argc, char const *argv[])
  4. {
  5. printf("%d\n", int_size_is_32());
  6. return 0;
  7. }
  8. int int_size_is_32()
  9. {
  10. int set_msb = 1 << 31;
  11. int beyond_msb = set_msb;
  12. beyond_msb <<= 1;
  13. return set_msb && !beyond_msb;
  14. }

编译运行输出:

  1. frank@under:~/tmp$ gcc 267.c && ./a.out
  2. 1

C:

  1. #include <stdio.h>
  2. int int_size_is_32();
  3. int main(int argc, char const *argv[])
  4. {
  5. printf("%d\n", int_size_is_32());
  6. return 0;
  7. }
  8. int int_size_is_32()
  9. {
  10. int set_msb = 1 << 15;
  11. set_msb <<= 15;
  12. set_msb <<= 1;
  13. int beyond_msb = set_msb;
  14. beyond_msb <<= 1;
  15. return set_msb && !beyond_msb;
  16. }

2.68

  1. #include <stdio.h>
  2. int lower_one_mask(int n);
  3. int main(int argc, char const *argv[])
  4. {
  5. printf("%#.8x\n", lower_one_mask(6));
  6. printf("%#.8x\n", lower_one_mask(17));
  7. return 0;
  8. }
  9. int lower_one_mask(int n)
  10. {
  11. int sizeof_int = sizeof(int);
  12. unsigned x = ~0;
  13. x >>= ((sizeof_int << 3) - n);
  14. return x;
  15. }

编译运行输出:

  1. frank@under:~/tmp$ gcc 268.c && ./a.out
  2. 0x0000003f
  3. 0x0001ffff

2.69

  1. #include <stdio.h>
  2. unsigned rotate_left(unsigned x, int n);
  3. int main(int argc, char const *argv[])
  4. {
  5. unsigned x = 0x12345678;
  6. printf("%#.8x\n", rotate_left(x, 0));
  7. printf("%#.8x\n", rotate_left(x, 4));
  8. printf("%#.8x\n", rotate_left(x, 20));
  9. return 0;
  10. }
  11. unsigned rotate_left(unsigned x, int n)
  12. {
  13. unsigned sizeof_unsigned = sizeof(unsigned);
  14. unsigned w = sizeof_unsigned << 3;
  15. unsigned mask = ((1 << n)-1) << (w-n);
  16. unsigned cache = (mask & x) >> (w-n);
  17. x <<= n;
  18. return x | cache;
  19. }

关键点在于掩码的产生和移除位数据的保存。

编译运行输出:

  1. frank@under:~/tmp$ gcc 269.c && ./a.out
  2. 0x12345678
  3. 0x23456781
  4. 0x67812345

2.70

  1. #include <stdio.h>
  2. #include <limits.h>
  3. int fits_bits(int x, int n);
  4. int main(int argc, char const *argv[])
  5. {
  6. /*test short and 31bits*/
  7. printf("%d\n", fits_bits(-32768, 16));
  8. printf("%d\n", fits_bits(32767, 16));
  9. printf("%d\n", fits_bits(INT_MAX, 32));
  10. printf("%d\n", fits_bits(INT_MIN, 32));
  11. printf("%d\n", fits_bits(0, 16));
  12. printf("%d\n", fits_bits(0, 32));
  13. printf("%d\n", fits_bits(32768, 16));
  14. printf("%d\n", fits_bits(-32769, 16));
  15. printf("%d\n", fits_bits(INT_MIN, 31));
  16. printf("%d\n", fits_bits(INT_MAX, 31));
  17. return 0;
  18. }
  19. int fits_bits(int x, int n)
  20. {
  21. unsigned sizeof_int = sizeof(int);
  22. unsigned w = sizeof_int << 3;
  23. int y = x << (w-n) >> (w-n);
  24. return y == x;
  25. }

编译运行输出:

  1. frank@under:~/tmp$ gcc 270.c && ./a.out
  2. 1
  3. 1
  4. 1
  5. 1
  6. 1
  7. 1
  8. 0
  9. 0
  10. 0
  11. 0

2.71

  1. /* Declaration of data type where 4 bytes are packed into an unsigned */
  2. typedef unsigned packed_t;
  3. /* Extract byte from word. Return as signed integer */
  4. int xbytte(packed_t word, int bytenum);
  5. /*That is, the function will extract the designated byte and sign extend it to be
  6. a 32-bit int.
  7. Your predecessor (who was fired for incompetence) wrote the following code:*/
  8. //Failed attempt at xbyte:
  9. int xbyte(packed_t word, int bytenum)
  10. {
  11. return (word>> (bytenum << 3)) & OxFF;
  12. }
  13. //A. What is wrong with this code?
  14. //B. Give a correct implementation of the function that uses only left and right
  15. //shifts, along with one subtraction.

A:

当取出的字节为负数时,由于原操作“粗暴”的将高位置零,会返回一个错误的正值。

B:

  1. #include <stdio.h>
  2. typedef unsigned packed_t;
  3. int xbytte(packed_t word, int bytenum);
  4. int main(int argc, char const *argv[])
  5. {
  6. packed_t word = 0x8008FF00;
  7. printf("%d\n", xbytte(word, 0));
  8. printf("%d\n", xbytte(word, 1));
  9. printf("%d\n", xbytte(word, 2));
  10. printf("%d\n", xbytte(word, 3));
  11. return 0;
  12. }
  13. int xbytte(packed_t word, int bytenum)
  14. {
  15. unsigned left_move = (3 - bytenum) << 3;
  16. unsigned right_move = (3) << 3;
  17. return (int)word << left_move >> right_move;
  18. }

编译运行输出:

  1. frank@under:~/tmp$ gcc 271.c && ./a.out
  2. 0
  3. -1
  4. 8
  5. -128

2.72

  1. /*BUGGY: Copy integer into buffer if space is available */
  2. void copy_int(int val; void *buf, int maxbytes)
  3. {
  4. if (maxbytes-sizeof(val) >= 0)
  5. memcpy(buf, (void*) &val, sizeof(val));
  6. }

A:

sizeof返回的类型为size_t:

According to the 1999 ISO C standard (C99), size_t is an unsigned integer type of at least 16 bit (see sections 7.17 and 7.18.3).

size_tis an unsigned data type defined by several C/C++ standards, e.g. the C99 ISO/IEC 9899 standard, that is defined in stddef.h.1 It can be further imported by inclusion ofstdlib.h as this file internally sub includes stddef.h.

所以maxbytes-sizeof(val)将一直转化为无符号数并永远大于等于零。

B:

  1. void copy_int(int val; void *buf, int maxbytes)
  2. {
  3. if(maxbytes < 0)
  4. return;
  5. if (maxbytes >= sizeof(val))
  6. memcpy(buf, (void*) &val, sizeof(val));
  7. }

2.73

  1. #include <stdio.h>
  2. #include <limits.h>
  3. int saturating_add(int x, int y);
  4. int main(int argc, char const *argv[])
  5. {
  6. printf("%d\n", saturating_add(123456, -54321));
  7. printf("%d\n", saturating_add(2147483647, 1));
  8. printf("%d\n", saturating_add(-2147483648, -1));
  9. return 0;
  10. }
  11. int saturating_add(int x, int y)
  12. {
  13. unsigned sizeof_int = sizeof(int);
  14. unsigned w = sizeof_int << 8;
  15. int i = (x ^ y) >> (w-1);//+-:FFFFFFFF ++/--:00000000
  16. int j = ((x+y) ^ x) >> (w-1);//overflow:FFFFFFFF otherwise:00000000
  17. int k = x >> (w-1);//+:00000000 -:FFFFFFFF
  18. return (i & (x + y)) + (~i & (j & ( (~k & INT_MAX) + (k & INT_MIN) )));
  19. }

解释一下i j k:这三个变量和与运算结合用来做“判断语句”,i通过x,y是否异号判断是否可能溢出,j通过结果和加数的符号判断在同号的情况下是否发生溢出。k判断是应该返回INT_MAX 还是 INT_MIN。

编译运行输出:

  1. frank@under:~/tmp$ gcc 273.c && ./a.out
  2. 69135
  3. 2147483647
  4. -2147483648

2.74

  1. #include <stdio.h>
  2. #include <limits.h>
  3. int tsub_ok(int x, int y);
  4. int main(int argc, char const *argv[])
  5. {
  6. printf("%d\n", tsub_ok(123456, 54321));
  7. printf("%d\n", tsub_ok(2147483647, -1));
  8. printf("%d\n", tsub_ok(-2147483648, 1));
  9. return 0;
  10. }
  11. int tsub_ok(int x, int y)
  12. {
  13. unsigned sizeof_int = sizeof(int);
  14. unsigned w = sizeof_int << 8;
  15. y = -y;
  16. int i = (x ^ y) >> (w-1);//+-:FFFFFFFF ++/--:00000000
  17. int j = ((x+y) ^ x) >> (w-1);//overflow:FFFFFFFF otherwise:00000000
  18. return i || ~j;
  19. }

原理与2.73类似。

编译运行输出:

  1. frank@under:~/tmp$ gcc 274.c && ./a.out
  2. 1
  3. 0
  4. 0

2.75

  1. #include <stdio.h>
  2. #include <stdint.h>
  3. #include <stdbool.h>
  4. unsigned unsigned_high_prod(unsigned x, unsigned y);
  5. int signed_high_prod(int x, int y);
  6. int main(int argc, char const *argv[])
  7. {
  8. /* code */
  9. return 0;
  10. }
  11. unsigned unsigned_high_prod(unsigned x, unsigned y)
  12. {
  13. unsigned w = sizeof(int32_t) << 3;
  14. int64_t signed_total_prod = signed_high_prod(x, y);
  15. signed_total_prod <<= w;
  16. signed_total_prod += x*y;
  17. bool x_w = x < 0 ? true : false;
  18. bool y_w = y < 0 ? true : false;
  19. int64_t unsigned_total_prod = signed_total_prod + ((x_w*(int)y + y_w*(int)x)<<w) + x_w*y_w<<(w*2);
  20. return (unsigned)(unsigned_total_prod>>w);
  21. }

原理参见树上2.18等式。


2.76

  1. void *calloc(size_t nmemb, size_t size)
  2. {
  3. void *p;
  4. if(!(nmemb*size) || !(p = malloc(size*nmemb)))
  5. return NULL;
  6. else if (((size_t)(nmemb*size))/size != nmemb)
  7. /* __builtin_umull_overflow() works too */
  8. {
  9. /* Thanks to zhzhwz who found a forget-to-free problem here.
  10. Maybe we should write a free_and_return_NULL block
  11. and goto it specifically.
  12. */
  13. fprintf(stderr, "size*nmemb overflow size_t.\n");
  14. free(p);
  15. return NULL;
  16. }
  17. else
  18. {
  19. memset(p, 0, size*nmemb);
  20. return p;
  21. }
  22. }

2.77

  1. #include <stdio.h>
  2. int main(int argc, char const *argv[])
  3. {
  4. unsigned sizeof_int = sizeof(int);
  5. unsigned w = sizeof_int << 3;
  6. int x = 1;
  7. printf("%d\n", (x << 4) + x);//k=17
  8. printf("%d\n", x - (x << 3));//k=-7
  9. printf("%d\n", (x << 6) - (x << 2));//k=60
  10. printf("%d\n", (x << 4) - (x << 7));//k=-112
  11. return 0;
  12. }

编译运行输出:

  1. frank@under:~/tmp$ gcc 277.c && ./a.out
  2. 17
  3. -7
  4. 60
  5. -112

2.78

  1. #include <stdio.h>
  2. int divide_power2(int x, int k);
  3. int main(int argc, char const *argv[])
  4. {
  5. printf("%d\n", divide_power2(1024, 2));
  6. printf("%d\n", divide_power2(5, 2));
  7. printf("%d\n", divide_power2(-1024, 2));
  8. printf("%d\n", divide_power2(-5, 2));
  9. return 0;
  10. }
  11. int divide_power2(int x, int k)
  12. {
  13. int bias = (1 << k) - 1;
  14. unsigned sizeof_int = sizeof(int);
  15. unsigned w = sizeof_int << 3;
  16. int judge = x >> (w-1); //-:FFFFFFFF +:00000000
  17. return (judge & ((x + bias) >> k)) + (~judge & (x >> k));
  18. }

编译运行输出:

  1. frank@under:~/tmp$ gcc 278.c && ./a.out
  2. 256
  3. 1
  4. -256
  5. -1

2.79

  1. int mul3div4(int x)
  2. {
  3. int k = 2;
  4. int bias = (1 << k) - 1;
  5. unsigned sizeof_int = sizeof(int);
  6. unsigned w = sizeof_int << 3;
  7. x = (x << 1) + x;
  8. int judge = x >> (w-1); //-:FFFFFFFF +:00000000
  9. return (judge & ((x + bias) >> k)) + (~judge & (x >> k));
  10. }

2.80

[BUG] threefourths(3)应计算得到2,代码将会得到0,可以参考 2.80

From: zhzhwz

  1. int threefourths(int x)
  2. {
  3. int k = 2;
  4. int bias = (1 << k) - 1;
  5. unsigned sizeof_int = sizeof(int);
  6. unsigned w = sizeof_int << 3;
  7. int judge = x >> (w-1); //-:FFFFFFFF +:00000000
  8. x = (judge & ((x + bias) >> k)) + (~judge & (x >> k));
  9. return (x << 1) + x;
  10. }

参考2.78


2.81

A:

  1. x = ~0 << k;

B:

  1. x = ~(~0 << k) << j;

2.82

A: when x = INT_MIN, y = 0. Yields 0

B: It always yields 1. Say, "mod" = mod 2^32. LEFT = ((((((x+y)mod)*16)mod)+y)mod)-x)mod = (17y + 15x)mod. RIGHT = (17*y)mod + (15*x)mod = (17y + 15x)mod.

C: It always yields 1. LEFT = (~x + 1) + (~y + 1) - 1 = -x + -y - 1. RIGHT = ~(x+y) + 1 - 1 = -(x+y) - 1 = -x + -y - 1.

D: It always yields 1. Since whether a integer type data is a int or unsigned doesn't influence the implementations of subtraction or unary minus operators.

(写到一半突然发现是用英文写的,可能是看教材影响的。。。)

E: 永远产生1,因为x先向右移动,再向左移动相同的位置,所以数据的高位不会受到影响。但是如果低两位有1的话,会都变为0。因为低位的1在补码中无论对于负数还是正数都是加的。所以对于正数来说,值会变小或者不变;对于0来说,值会不变;对于负数来说,值会变小或者不变。


2.83

A:

根据提示:Y = x*2^k - x 即 x = Y/(2^k - 1)

B:

由A:(a) Y = 101 = 5, k = 3, x = 5/7 (b) Y = 0110 = 6, k = 4, x = 2/5 (c) Y = 010011 = 19, k = 6, x = 19/63


2.84

  1. #include <stdio.h>
  2. int float_le(float x, float y);
  3. unsigned f2u(float x);
  4. int main(int argc, char const *argv[])
  5. {
  6. printf("%d\n", float_le((float)1.11, (float)1.10));
  7. printf("%d\n", float_le((float)-1.2, (float)3.0));
  8. printf("%d\n", float_le((float)1.3, (float)1.3));
  9. printf("%d\n", float_le((float)0, (float)0));
  10. printf("%d\n", float_le((float)-1.1, (float)0));
  11. printf("%d\n", float_le((float)0, (float)1.1));
  12. return 0;
  13. }
  14. unsigned f2u(float x)
  15. {
  16. return *(unsigned*)&x;
  17. }
  18. int float_le(float x, float y)
  19. {
  20. unsigned ux = f2u(x);
  21. unsigned uy = f2u(y);
  22. /*Get the sign bits*/
  23. unsigned sx = ux >> 31; //+:0 -:1
  24. unsigned sy = uy >> 31;
  25. /* Give an expression using only ux, uy, sx, and sy */
  26. return (sx ^ sy) ? (sx ? 1 : 0)/*-+ +-*/ : (sx ? (ux>=uy) : (ux<=uy))/*-- ++*/;
  27. }

编译运行输出:

  1. frank@under:~/tmp$ gcc 284.c && ./a.out
  2. 0
  3. 1
  4. 1
  5. 1
  6. 1
  7. 1

[PATCH] +0和-0不等

From: zhzhwz

  1. @@ -11,6 +11,7 @@ int main(int argc, char const *argv[])
  2. printf("%d\n", float_le((float)0, (float)0));
  3. printf("%d\n", float_le((float)-1.1, (float)0));
  4. printf("%d\n", float_le((float)0, (float)1.1));
  5. printf("%d\n", float_le((float)(1/1e100), (float)(-1/1e100)));
  6. return 0;
  7. }
  8. @@ -28,5 +29,5 @@ int float_le(float x, float y)
  9. unsigned sy = uy >> 31;
  10. /* Give an expression using only ux, uy, sx, and sy */
  11. return (sx ^ sy) ? (sx ? 1 : 0)/-+ +-/ : (sx ? (ux>=uy) : (ux<=uy))/-- ++/;
  12. return (ux << 1 == 0 && uy << 1 == 0)/all 0/ || ((sx ^ sy) ? (sx ? 1 : 0)/-+ +-/ : (sx ? (ux>=uy) : (ux<=uy))/-- ++/);
  13. }
  14. \ No newline at end of file

2.85

bias = 2^(k-1) - 1 suppose that k <= n

A:

E = 0b10+bias, M = 0b1.11, f = ob1100*, V = 1.0

bit representation: 0, 0b10+bias, 1100*

B:

E = n+bias, M = 0b1.11*, f = 0b11*, V = 2^(n+1)-1

bit representation: 0, n+bias, 11*

C:

The smallest positive normalized value : E = 0b00*1, M = 0b1.00*, f = 0b00*, V = 1.0

So the reciprocal is exactly the same number.


2.86

bias = 2^14 - 1

Smallest positive denormalized:

Value: 0, 00*, 0, 00*1 Decimal:2(2-214) * 2^(-63)

Smallest positive normalized:

Value: 0, 00*1, 1, 00* Decimal:2(2-214)

Largest normalized:

Value: 0, 11*0, 1, 11* Decimal: 2(214-1) * (2-2^(-63))


2.872.88本来在Typora上是用表格写的,上传上来好像有格式问题,将就看一下 ; )

2.87

| Description | Hex | M | E | V | D |

| -0 | 8000 | 0 | -14 | 0 | 0 |

| Smallest value > 2 | 4001 | 1025/1024 | 1 | 10252^-8 | 2.001953 |

| 512 | 6000 | 1 | 9 | 1
2^9 | 512.000000 |

| Largest denormalized | 0311 | 1023/1024 | -14 | 10232^-24 | 0.000061 |

| negative infinite | FC00 | - | - | - | -inf |

| 3BB0 | 3BB0 | 124/64 | -1 | 31
2^-5 | 0.968750 |


2.88

| Format A | Format A | Format B | Format B |

| Bits | Value | Bits | Value |

| 1 01111 001 | -9/8 | 1 0111 0010 | -9/8 |

| 0 10110 011 | 112^4 | 0 1110 0110 | 112^4 |

| 1 00111 010 | -52^-10 | 1 0000 0101 | -52^-10 |

| 0 00000 111 | 72^-17 | 0 0000 0001 | 2^-10 |

| 1 11100 000 | -2^13 | 1 1110 1111 | -31
2^3 |

| 0 10111 100 | 32^7 | 0 1110 1111 | 312^3 |


2.89

A:总是返回1.因为int到double不会有精度上的损失,所以x,dx转float(损失精度)的结果是一样的。

B:不总是返回1.如x=INT_MIN,Y=1。

[PATCH] 注意2.89的C中dz是由一个整数转换来的,因此不会取到1e-30

From: zhzhwz

  1. - C:不总是返回1.浮点数不满足结合律,如dx=1e30, dy=-1e30, dz=1e-30
  2. + C:由于int转换为double不会有精度上的损失,且在int范围内使用double做加法得到的结果一定是精确的(这是因为double的尾数足以容纳32bit),因此满足结合律。

D:不总是返回1.原因同上。例如dx与dy互为倒数且dy*dz=+infinite。

E:不总是返回1.例如dx=1.0, dz=0.0 。


2.90

  1. float fpwr2(int x)
  2. {
  3. /* Result exponent and fraction */
  4. unsigned exp, frac;
  5. unsigned u;
  6. if (x < -149)
  7. {
  8. /* Too small. Return 0.0 */
  9. exp = 0;
  10. frac = 0;
  11. }
  12. else if (x < -126)
  13. {
  14. /* Denormalized result */
  15. exp = 0;
  16. frac = 1 << (149 + x);
  17. }
  18. else if (x < 128)
  19. {
  20. /* Normalized result. */
  21. exp = x + 127;
  22. frac = 0;
  23. }
  24. else
  25. {
  26. /* Too big. Return +oo */
  27. exp = 0xFF;
  28. frac = 0;
  29. }
  30. /*Pack exp and frac into,32 bits */
  31. u = exp << 23 | frac;
  32. /* Return as float */
  33. return u2f(u);
  34. }

2.91

0x 40490FDB = 0b 0100 0000 0100 1001 0000 1111 1101 1011 = 0,10000000,10010010000111111011011

A: 10010010000111111011011

B: (详情可见)2.83 y=1, k=3, 即 0b11.(001)*

C: 0x4049039b 0x40492492 从高位向低位第19个。



浮点数部分由于时间所限,没有进行相关测试,思路大致应该是对的,可能会有一些边界/特殊情况会产生问题,欢迎指出。

2.92

  1. float_bits float_negate(float_bits f)
  2. {
  3. unsigned sign = f >> 31;
  4. unsigned exp = f >> 23 & 0xFF;
  5. unsigned frac = f & 0x7FFFFF;
  6. if(!(exp ^ 0xFF) && frac)
  7. {
  8. return f;
  9. }
  10. else
  11. {
  12. sign = !sign;
  13. return (sign << 31) | (exp << 23) | frac;
  14. }
  15. }

2.93

  1. float_bits float_absval(float_bits f)
  2. {
  3. unsigned exp = f >> 23 & 0xFF;
  4. unsigned frac = f & 0x7FFFFF;
  5. if(!(exp ^ 0xFF) && frac)
  6. {
  7. return f;
  8. }
  9. return (exp << 23) | frac;
  10. }

2.94

  1. float_bits float_twice(float_bits f)
  2. {
  3. unsigned sign = f >> 31;
  4. unsigned exp = f >> 23 & 0xFF;
  5. unsigned frac = f & 0x7FFFFF;
  6. if(!(exp ^ 0xFF))
  7. {
  8. if (frac)//NaN
  9. {
  10. return f;
  11. }
  12. /*else
  13. {
  14. return (sign << 31) | (exp << 23) | frac;//infinite
  15. }*/
  16. }
  17. else//Denormalnized and normalized
  18. {
  19. if (exp)//Normalnized
  20. {
  21. if (!(frac >> 22))
  22. {
  23. frac <<= 1;
  24. //return (sign << 31) | (exp << 23) | frac;
  25. }
  26. else if (!(exp ^ 0xFE))
  27. {
  28. ++exp;
  29. //return (sign << 31) | (exp << 23) | frac;
  30. }
  31. else//overflow
  32. {
  33. frac = 0;
  34. exp = 0xFF;
  35. //return (sign << 31) | (exp << 23) | frac;
  36. }
  37. }
  38. else//Denormalized
  39. {
  40. if (!(frac >> 22))
  41. {
  42. frac <<= 1;
  43. //return (sign << 31) | (exp << 23) | frac;
  44. }
  45. else//Turn to Normalized
  46. {
  47. ++exp;
  48. frac = frac << 10 >> 9;//set the 23th bit of frac to 0 and then left shift one bit.(注释是必要的。。。过了几天看这一段的时候自己也没弄懂,忘了这里frac是一个unsigned。。。)
  49. //return (sign << 31) | (exp << 23) | frac;
  50. }
  51. }
  52. }
  53. return (sign << 31) | (exp << 23) | frac;
  54. }

2.95

  1. float_bits float_half(float_bits f)
  2. {
  3. unsigned sign = f >> 31;
  4. unsigned exp = f >> 23 & 0xFF;
  5. unsigned frac = f & 0x7FFFFF;
  6. if(!(exp ^ 0xFF))
  7. {
  8. if (frac)//NaN
  9. {
  10. return f;
  11. }
  12. /*else
  13. {
  14. return (sign << 31) | (exp << 23) | frac;//infinite
  15. }*/
  16. }
  17. else//Denormalnized and normalized
  18. {
  19. if (exp)//Normalnized
  20. {
  21. if (exp != 1)
  22. {
  23. --exp;
  24. //return (sign << 31) | (exp << 23) | frac;
  25. }
  26. else//Turn to Denormalnized
  27. {
  28. if (frac)//maybe need to round to even
  29. {
  30. if ((frac >> 1)&1)
  31. {
  32. ++frac;
  33. frac >>= 1;
  34. frac |= 0x400000;
  35. --exp;
  36. }
  37. else
  38. {
  39. frac >>=1;
  40. frac |= 0x400000;
  41. --exp;
  42. }
  43. }
  44. }
  45. }
  46. else//Denormalized
  47. {
  48. if (frac)//maybe need to round to even
  49. {
  50. if ((frac >> 1)&1)
  51. {
  52. ++frac;
  53. frac >>= 1;
  54. }
  55. else
  56. {
  57. frac >>= 1;
  58. }
  59. }
  60. }
  61. }
  62. return (sign << 31) | (exp << 23) | frac;
  63. }

2.96

  1. int float_f2i(float_bits f)
  2. {
  3. unsigned sign = f >> 31;
  4. unsigned exp = f >> 23 & 0xFF;
  5. unsigned frac = f & 0x7FFFFF;
  6. unsigned bias = 127;
  7. int flag = 0;
  8. if(sign)//<=0
  9. {
  10. if (f < 0xBF800000)//>-1
  11. {
  12. return 0;
  13. }
  14. else if (f <= 0xCF000000)
  15. {
  16. if (f == 0xCF000000)//INT_MIN
  17. {
  18. return INT_MIN;//0x80000000;
  19. }
  20. else
  21. {
  22. f &= 0x7FFFFFFF;//first treat it as a positive number
  23. flag = 1;
  24. goto A;
  25. B:
  26. return (~f + 1);//-(+int)
  27. }
  28. }
  29. else//overflow/-infinite/NaN
  30. {
  31. return 0x80000000;
  32. }
  33. }
  34. else//>=0
  35. {
  36. if (f < 0x3F800000)//<1//Denormalnized->0
  37. {
  38. return 0;
  39. }
  40. else if (f <= 0x4EFFFFFF)
  41. {
  42. A:
  43. frac |= 0x800000;
  44. unsigned move = 23 - (exp-bias);
  45. if (flag)//jumped from a negative number
  46. {
  47. f = move >= 0 ? frac >> move : frac << -move;
  48. goto B;
  49. }
  50. else
  51. {
  52. return move >= 0 ? frac >> move : frac << -move;
  53. }
  54. }
  55. else//overflow/+infinite/NaN
  56. {
  57. return 0x80000000;
  58. }
  59. }
  60. }
  1. 标准答案
  2. /* Compute (int) f. If conversion causes overflow or f is NaN, return 0x80000000 */
  3. int float_f2i(float_bits f) {
  4. unsigned sign = f >> 31;
  5. unsigned exp = (f >> 23) & 0xFF;
  6. unsigned frac = f & 0x7FFFFF;
  7. /* Create normalized value with leading one inserted, and rest of significand in bits 8--30./
  8. unsigned val = 0x80000000u + (frac << 8);
  9. if (exp < 127) {
  10. /* Absolute value is < 1 */
  11. return (int) 0;
  12. }
  13. if (exp > 158)
  14. /* Overflow */
  15. return (int) 0x80000000u;
  16. /* Shift val right */
  17. val = val >> (158 - exp);
  18. /* Check if out of range */
  19. if (sign) {
  20. /* Negative */
  21. return val > 0x80000000u ? (int) 0x80000000u : -(int) val;
  22. } else {
  23. /* Positive */
  24. return val > 0x7FFFFFFF ? (int) 0x80000000u : (int) val;
  25. }
  26. }

2.97

  1. int leftmost_one(unsigned x)
  2. {
  3. unsigned sizeof_unsigned = sizeof(unsigned);
  4. unsigned w = sizeof_unsigned << 3;
  5. x |= x >> 1;
  6. x |= x >> 2;
  7. x |= x >> 4;
  8. x |= x >> 8;
  9. x |= x >> 16;
  10. return x & ((~x >> 1)|INT_MIN);
  11. }
  12. float_bits float_i2f(int i)
  13. {
  14. unsigned sign = 0;
  15. unsigned exp = 0;
  16. unsigned frac = 0;
  17. unsigned bias = 127;
  18. if (i == INT_MIN)
  19. {
  20. return 0xCF000000;
  21. }
  22. else//treat negative as positive
  23. {
  24. if (i < 0)
  25. {
  26. sign = 1;
  27. i = -i;
  28. }
  29. int mask = leftmost_one(i);
  30. int move = 0;
  31. if (mask >= 0x00800000)//rightshift
  32. {
  33. while(mask != 0x00800000)
  34. {
  35. mask >>= 1;
  36. ++move;
  37. }
  38. if ((i & ((1 << (move+1)) - 1)) > (1 << move))//round to even(>1/2)
  39. {
  40. i >>= move;
  41. i += 1;
  42. }
  43. else if((i & ((1 << (move+1)) - 1)) < (1 << move))//(<1/2)
  44. {
  45. i >>= move;
  46. }
  47. else// 1/2
  48. {
  49. if ((i >> move)&1)//round to even
  50. {
  51. i >>= move;
  52. i += 1;
  53. }
  54. else
  55. {
  56. i >>= move;
  57. }
  58. }
  59. }
  60. else//leftshift
  61. {
  62. while(mask != 0x00800000)
  63. {
  64. mask <<= 1;
  65. --move;
  66. }
  67. i <<= -move;
  68. }
  69. frac = i & 0x7FFFFF;//Discard the 24th bit one
  70. exp = bias + 22 + move;
  71. }
  72. return (sign << 31) | (exp << 23) | frac;
  73. }

用到了2.66产生标志整数最高位1掩码,从而判断应该左移或者右移多少位。

深入理解计算机系统_3e 第二章家庭作业答案的更多相关文章

  1. 深入理解计算机系统_3e 第二章家庭作业 CS:APP3e chapter 2 homework

    初始完成日期:2017.9.26 许可:除2.55对应代码外(如需使用请联系 randy.bryant@cs.cmu.edu),任何人可以自由的使用,修改,分发本文档的代码. 本机环境: (有一些需要 ...

  2. 深入理解计算机系统_3e 第九章家庭作业 CS:APP3e chapter 9 homework

    9.11 A. 00001001 111100 B. +----------------------------+ | Parameter Value | +--------------------- ...

  3. 深入理解计算机系统_3e 第八章家庭作业 CS:APP3e chapter 8 homework

    8.9 关于并行的定义我之前写过一篇文章,参考: 并发与并行的区别 The differences between Concurrency and Parallel +---------------- ...

  4. 深入理解计算机系统_3e 第十章家庭作业 CS:APP3e chapter 10 homework

    10.6 1.若成功打开"foo.txt": -->1.1若成功打开"baz.txt": 输出"4\n" -->1.2若未能成功 ...

  5. CSAPP深入理解计算机系统(第二版)第三章家庭作业答案

    <深入理解计算机系统(第二版)>CSAPP 第三章 家庭作业 这一章介绍了AT&T的汇编指令 比较重要 本人完成了<深入理解计算机系统(第二版)>(以下简称CSAPP) ...

  6. 深入理解计算机系统_3e 第四章家庭作业(部分) CS:APP3e chapter 4 homework

    4.52以后的题目中的代码大多是书上的,如需使用请联系 randy.bryant@cs.cmu.edu 更新:关于编译Y86-64中遇到的问题,可以参考一下CS:APP3e 深入理解计算机系统_3e ...

  7. <深入理解计算机系统>第七章读书笔记

    第七章读书笔记 链接 链接:将各种代码和数据部分收集起来并组合成为一个单一文件的过程.(这个文件可被加载或拷贝到存储器并执行) 链接可以执行于编译,加载或运行时. 静态链接: 两个主要任务: 1 符号 ...

  8. Python编程快速上手-让繁琐工作自动化-第二章习题及其答案

    Python编程快速上手-让繁琐工作自动化-第二章习题及其答案 1.布尔数据类型的两个值是什么?如何拼写? 答:True和False,使用大写的T和大写的F,其他字母是小写. 2.3个布尔操作符是什么 ...

  9. 深入理解计算机系统 Start && 第一章要点

    对此书已经慕名已久了,抽空看了第1,2,3,5章,其他章节等有空闲继续看吧. 我的许多博客是给自己快速复习使用的,比如此读书后感,你可以根据我下面的建议读完原书几章再回来复习一下(或许那时候就没必要回 ...

随机推荐

  1. 迈向angularjs2系列(8):angular cli和angular2种子项目

    文章目录 1.angular cli快速搭建项目 2.angular2-seed 3.手动配置 题外话:如何更好的阅读本篇文章 一: angular cli的安装 Angular-cli(命令行界面, ...

  2. Java面试准备之集合框架

    集合框架 Collection:List列表,Set集 Map:Hashtable,HashMap,TreeMap Collection 是单列集合 List 元素是有序的(元素存取是有序).可重复 ...

  3. 斐波那契数列—Java

    斐波那契数列想必大家都知道吧,如果不知道的话,我就再啰嗦一遍, 斐波那契数列为:1 2 3 5 8 13 ...,也就是除了第一项和第二项为1以外,对于第N项,有f(N)=f(N-1)+f(N-2). ...

  4. 好用的sql

    @ 复制表结构 ; --复制表结构和数据 create table table_name_new as select * from <table_name> @ 查看表信息 select ...

  5. spring-session 共享

    Spring session 共享 一.引入依赖 <dependency> <groupId>redis.clients</groupId> <artifac ...

  6. vue父子组件通信

    一.父子组件间通信 vue.js 2.0提供了一个ref 的属性: 可以为子组件指定一个索引id 父组件: <template> <div id='user-login'> & ...

  7. JVM启动参数设置

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt174 不管是YGC还是Full GC,GC过程中都会对导致程序运行中中断,正 ...

  8. 大型网站的 HTTPS 实践(三)——基于协议和配置的优化

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt389 1 前言 上文讲到 HTTPS 对用户访问速度的影响. 本文就为大家介 ...

  9. css编写注意事项(不定时更新)

    CSS的编写是需要积累的,而一个好的css编写习惯对我们将来的成长是非常有利的,我会把我平时看到的或者遇到的会不定时的更新到这里,不时翻一下,但求有所进步. 如果各位看官也有看法和建议,评论下,我也会 ...

  10. Linux运维:安装CentOS7.2-图解

    矮哥linux运维群: 93324526 笔者QQ:578843228 此篇博文针对最小化安装,和只有图解.有不懂地方,欢迎加群询问.