计算机系统基础
本学期我们主要学习了:
1.数据的表示和存储
2.运算电路基础
3.乘除运算及浮点数运算
4.IA32指令系统概述
5.IA32指令类型
6.C语言的语句的机器级表示
那么我们来回忆并总结一下本学期的主要内容,主要以代码运行的方式进行:
一、汇编代码的生成以及初步互译
/* Demonstration of buffer overflow */
#include <stdio.h>
#include <stdlib.h>
/* Implementation of library function gets() */
char *gets(char *dest)
{
int c = getchar();
char *p = dest;
while (c != EOF && c != '\n') {
*p++ = c;
c = getchar();
}
*p = '\0';
return dest;
}
/* Read input line and write it back */
void echo()
{
char buf[4]; /* Way too small! */
gets(buf);
puts(buf);
}
void call_echo()
{
echo();
}
/*void smash()
{
printf("I've been smashed!\n");
exit(0);
}
*/
int main()
{
printf("Type a string:");
call_echo();
return 0;
}
将其进行汇编:
Disassembly of section .init:
08048354 <_init>:
8048354: 53 push %ebx
8048355: 83 ec 08 sub $0x8,%esp
8048358: e8 c3 00 00 00 call 8048420 <__x86.get_pc_thunk.bx>
804835d: 81 c3 a3 1c 00 00 add $0x1ca3,%ebx
8048363: 8b 83 fc ff ff ff mov -0x4(%ebx),%eax
8048369: 85 c0 test %eax,%eax
804836b: 74 05 je 8048372 <_init+0x1e>
804836d: e8 5e 00 00 00 call 80483d0 <__gmon_start__@plt>
8048372: 83 c4 08 add $0x8,%esp
8048375: 5b pop %ebx
8048376: c3 ret
Disassembly of section .plt:
08048380 <printf@plt-0x10>:
8048380: ff 35 04 a0 04 08 pushl 0x804a004
8048386: ff 25 08 a0 04 08 jmp *0x804a008
804838c: 00 00 add %al,(%eax)
...
08048390 <printf@plt>:
8048390: ff 25 0c a0 04 08 jmp *0x804a00c
8048396: 68 00 00 00 00 push $0x0
804839b: e9 e0 ff ff ff jmp 8048380 <_init+0x2c>
080483a0 <getchar@plt>:
80483a0: ff 25 10 a0 04 08 jmp *0x804a010
80483a6: 68 08 00 00 00 push $0x8
80483ab: e9 d0 ff ff ff jmp 8048380 <_init+0x2c>
080483b0 <__stack_chk_fail@plt>:
80483b0: ff 25 14 a0 04 08 jmp *0x804a014
80483b6: 68 10 00 00 00 push $0x10
80483bb: e9 c0 ff ff ff jmp 8048380 <_init+0x2c>
080483c0 <puts@plt>:
80483c0: ff 25 18 a0 04 08 jmp *0x804a018
80483c6: 68 18 00 00 00 push $0x18
80483cb: e9 b0 ff ff ff jmp 8048380 <_init+0x2c>
080483d0 <__gmon_start__@plt>:
80483d0: ff 25 1c a0 04 08 jmp *0x804a01c
80483d6: 68 20 00 00 00 push $0x20
80483db: e9 a0 ff ff ff jmp 8048380 <_init+0x2c>
080483e0 <__libc_start_main@plt>:
80483e0: ff 25 20 a0 04 08 jmp *0x804a020
80483e6: 68 28 00 00 00 push $0x28
80483eb: e9 90 ff ff ff jmp 8048380 <_init+0x2c>
Disassembly of section .text:
080483f0 <_start>:
80483f0: 31 ed xor %ebp,%ebp
80483f2: 5e pop %esi
80483f3: 89 e1 mov %esp,%ecx
80483f5: 83 e4 f0 and $0xfffffff0,%esp
80483f8: 50 push %eax
80483f9: 54 push %esp
80483fa: 52 push %edx
80483fb: 68 10 86 04 08 push $0x8048610
8048400: 68 a0 85 04 08 push $0x80485a0
8048405: 51 push %ecx
8048406: 56 push %esi
8048407: 68 77 85 04 08 push $0x8048577
804840c: e8 cf ff ff ff call 80483e0 <__libc_start_main@plt>
8048411: f4 hlt
8048412: 66 90 xchg %ax,%ax
8048414: 66 90 xchg %ax,%ax
8048416: 66 90 xchg %ax,%ax
8048418: 66 90 xchg %ax,%ax
804841a: 66 90 xchg %ax,%ax
804841c: 66 90 xchg %ax,%ax
804841e: 66 90 xchg %ax,%ax
08048420 <__x86.get_pc_thunk.bx>:
8048420: 8b 1c 24 mov (%esp),%ebx
8048423: c3 ret
8048424: 66 90 xchg %ax,%ax
8048426: 66 90 xchg %ax,%ax
8048428: 66 90 xchg %ax,%ax
804842a: 66 90 xchg %ax,%ax
804842c: 66 90 xchg %ax,%ax
804842e: 66 90 xchg %ax,%ax
08048430 <deregister_tm_clones>:
8048430: b8 2f a0 04 08 mov $0x804a02f,%eax
8048435: 2d 2c a0 04 08 sub $0x804a02c,%eax
804843a: 83 f8 06 cmp $0x6,%eax
804843d: 77 01 ja 8048440 <deregister_tm_clones+0x10>
804843f: c3 ret
8048440: b8 00 00 00 00 mov $0x0,%eax
8048445: 85 c0 test %eax,%eax
8048447: 74 f6 je 804843f <deregister_tm_clones+0xf>
8048449: 55 push %ebp
804844a: 89 e5 mov %esp,%ebp
804844c: 83 ec 18 sub $0x18,%esp
804844f: c7 04 24 2c a0 04 08 movl $0x804a02c,(%esp)
8048456: ff d0 call *%eax
8048458: c9 leave
8048459: c3 ret
804845a: 8d b6 00 00 00 00 lea 0x0(%esi),%esi
08048460 <register_tm_clones>:
8048460: b8 2c a0 04 08 mov $0x804a02c,%eax
8048465: 2d 2c a0 04 08 sub $0x804a02c,%eax
804846a: c1 f8 02 sar $0x2,%eax
804846d: 89 c2 mov %eax,%edx
804846f: c1 ea 1f shr $0x1f,%edx
8048472: 01 d0 add %edx,%eax
8048474: d1 f8 sar %eax
8048476: 75 01 jne 8048479 <register_tm_clones+0x19>
8048478: c3 ret
8048479: ba 00 00 00 00 mov $0x0,%edx
804847e: 85 d2 test %edx,%edx
8048480: 74 f6 je 8048478 <register_tm_clones+0x18>
8048482: 55 push %ebp
8048483: 89 e5 mov %esp,%ebp
8048485: 83 ec 18 sub $0x18,%esp
8048488: 89 44 24 04 mov %eax,0x4(%esp)
804848c: c7 04 24 2c a0 04 08 movl $0x804a02c,(%esp)
8048493: ff d2 call *%edx
8048495: c9 leave
8048496: c3 ret
8048497: 89 f6 mov %esi,%esi
8048499: 8d bc 27 00 00 00 00 lea 0x0(%edi,%eiz,1),%edi
080484a0 <__do_global_dtors_aux>:
80484a0: 80 3d 2c a0 04 08 00 cmpb $0x0,0x804a02c
80484a7: 75 13 jne 80484bc <__do_global_dtors_aux+0x1c>
80484a9: 55 push %ebp
80484aa: 89 e5 mov %esp,%ebp
80484ac: 83 ec 08 sub $0x8,%esp
80484af: e8 7c ff ff ff call 8048430 <deregister_tm_clones>
80484b4: c6 05 2c a0 04 08 01 movb $0x1,0x804a02c
80484bb: c9 leave
80484bc: f3 c3 repz ret
80484be: 66 90 xchg %ax,%ax
080484c0 <frame_dummy>:
80484c0: a1 10 9f 04 08 mov 0x8049f10,%eax
80484c5: 85 c0 test %eax,%eax
80484c7: 74 1f je 80484e8 <frame_dummy+0x28>
80484c9: b8 00 00 00 00 mov $0x0,%eax
80484ce: 85 c0 test %eax,%eax
80484d0: 74 16 je 80484e8 <frame_dummy+0x28>
80484d2: 55 push %ebp
80484d3: 89 e5 mov %esp,%ebp
80484d5: 83 ec 18 sub $0x18,%esp
80484d8: c7 04 24 10 9f 04 08 movl $0x8049f10,(%esp)
80484df: ff d0 call *%eax
80484e1: c9 leave
80484e2: e9 79 ff ff ff jmp 8048460 <register_tm_clones>
80484e7: 90 nop
80484e8: e9 73 ff ff ff jmp 8048460 <register_tm_clones>
080484ed <gets>:
80484ed: 55 push %ebp
80484ee: 89 e5 mov %esp,%ebp
80484f0: 83 ec 18 sub $0x18,%esp
80484f3: e8 a8 fe ff ff call 80483a0 <getchar@plt>
80484f8: 89 45 f0 mov %eax,-0x10(%ebp)
80484fb: 8b 45 08 mov 0x8(%ebp),%eax
80484fe: 89 45 f4 mov %eax,-0xc(%ebp)
8048501: eb 16 jmp 8048519 <gets+0x2c>
8048503: 8b 45 f4 mov -0xc(%ebp),%eax
8048506: 8d 50 01 lea 0x1(%eax),%edx
8048509: 89 55 f4 mov %edx,-0xc(%ebp)
804850c: 8b 55 f0 mov -0x10(%ebp),%edx
804850f: 88 10 mov %dl,(%eax)
8048511: e8 8a fe ff ff call 80483a0 <getchar@plt>
8048516: 89 45 f0 mov %eax,-0x10(%ebp)
8048519: 83 7d f0 ff cmpl $0xffffffff,-0x10(%ebp)
804851d: 74 06 je 8048525 <gets+0x38>
804851f: 83 7d f0 0a cmpl $0xa,-0x10(%ebp)
8048523: 75 de jne 8048503 <gets+0x16>
8048525: 8b 45 f4 mov -0xc(%ebp),%eax
8048528: c6 00 00 movb $0x0,(%eax)
804852b: 8b 45 08 mov 0x8(%ebp),%eax
804852e: c9 leave
804852f: c3 ret
08048530 <echo>:
8048530: 55 push %ebp
8048531: 89 e5 mov %esp,%ebp
8048533: 83 ec 28 sub $0x28,%esp
8048536: 65 a1 14 00 00 00 mov %gs:0x14,%eax
804853c: 89 45 f4 mov %eax,-0xc(%ebp)
804853f: 31 c0 xor %eax,%eax
8048541: 8d 45 f0 lea -0x10(%ebp),%eax
8048544: 89 04 24 mov %eax,(%esp)
8048547: e8 a1 ff ff ff call 80484ed <gets>
804854c: 8d 45 f0 lea -0x10(%ebp),%eax
804854f: 89 04 24 mov %eax,(%esp)
8048552: e8 69 fe ff ff call 80483c0 <puts@plt>
8048557: 8b 45 f4 mov -0xc(%ebp),%eax
804855a: 65 33 05 14 00 00 00 xor %gs:0x14,%eax
8048561: 74 05 je 8048568 <echo+0x38>
8048563: e8 48 fe ff ff call 80483b0 <__stack_chk_fail@plt>
8048568: c9 leave
8048569: c3 ret
0804856a <call_echo>:
804856a: 55 push %ebp
804856b: 89 e5 mov %esp,%ebp
804856d: 83 ec 08 sub $0x8,%esp
8048570: e8 bb ff ff ff call 8048530 <echo>
8048575: c9 leave
8048576: c3 ret
08048577 <main>:
8048577: 55 push %ebp
8048578: 89 e5 mov %esp,%ebp
804857a: 83 e4 f0 and $0xfffffff0,%esp
804857d: 83 ec 10 sub $0x10,%esp
8048580: c7 04 24 30 86 04 08 movl $0x8048630,(%esp)
8048587: e8 04 fe ff ff call 8048390 <printf@plt>
804858c: e8 d9 ff ff ff call 804856a <call_echo>
8048591: b8 00 00 00 00 mov $0x0,%eax
8048596: c9 leave
8048597: c3 ret
8048598: 66 90 xchg %ax,%ax
804859a: 66 90 xchg %ax,%ax
804859c: 66 90 xchg %ax,%ax
804859e: 66 90 xchg %ax,%ax
080485a0 <__libc_csu_init>:
80485a0: 55 push %ebp
80485a1: 57 push %edi
80485a2: 31 ff xor %edi,%edi
80485a4: 56 push %esi
80485a5: 53 push %ebx
80485a6: e8 75 fe ff ff call 8048420 <__x86.get_pc_thunk.bx>
80485ab: 81 c3 55 1a 00 00 add $0x1a55,%ebx
80485b1: 83 ec 1c sub $0x1c,%esp
80485b4: 8b 6c 24 30 mov 0x30(%esp),%ebp
80485b8: 8d b3 0c ff ff ff lea -0xf4(%ebx),%esi
80485be: e8 91 fd ff ff call 8048354 <_init>
80485c3: 8d 83 08 ff ff ff lea -0xf8(%ebx),%eax
80485c9: 29 c6 sub %eax,%esi
80485cb: c1 fe 02 sar $0x2,%esi
80485ce: 85 f6 test %esi,%esi
80485d0: 74 27 je 80485f9 <__libc_csu_init+0x59>
80485d2: 8d b6 00 00 00 00 lea 0x0(%esi),%esi
80485d8: 8b 44 24 38 mov 0x38(%esp),%eax
80485dc: 89 2c 24 mov %ebp,(%esp)
80485df: 89 44 24 08 mov %eax,0x8(%esp)
80485e3: 8b 44 24 34 mov 0x34(%esp),%eax
80485e7: 89 44 24 04 mov %eax,0x4(%esp)
80485eb: ff 94 bb 08 ff ff ff call *-0xf8(%ebx,%edi,4)
80485f2: 83 c7 01 add $0x1,%edi
80485f5: 39 f7 cmp %esi,%edi
80485f7: 75 df jne 80485d8 <__libc_csu_init+0x38>
80485f9: 83 c4 1c add $0x1c,%esp
80485fc: 5b pop %ebx
80485fd: 5e pop %esi
80485fe: 5f pop %edi
80485ff: 5d pop %ebp
8048600: c3 ret
8048601: eb 0d jmp 8048610 <__libc_csu_fini>
8048603: 90 nop
8048604: 90 nop
8048605: 90 nop
8048606: 90 nop
8048607: 90 nop
8048608: 90 nop
8048609: 90 nop
804860a: 90 nop
804860b: 90 nop
804860c: 90 nop
804860d: 90 nop
804860e: 90 nop
804860f: 90 nop
08048610 <__libc_csu_fini>:
8048610: f3 c3 repz ret
Disassembly of section .fini:
*/
我们可以从中获知一些汇编的方法及对应关系,下面说明汇编代码的生成过程:
1、预处理:linux> gcc -E -o t1.i t1.c
2、编译:linux> gcc -S -o t1.s t1.i or linux> gcc -S -o t1.s t1.c(生成t1.s汇编文件)
3、汇编:linux> gcc -c -o t1.o t1.s or linux> gcc -c -o t1.o t1.c(生成 t1.o文件)
4、连接:linux> gcc -o t1 t1.o or linux> -o t1 t1.c (生成可执行文件t1)
5、执行:linux> ./t1
……
linux>|
二、浮点数运算特点
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFSIZE 256
int main(int argc, char *argv[]) {
char prefix[BUFSIZE];
char next[BUFSIZE];
int i;
float sum = 0.0;
for (i = 1; i < argc; i++) {
float x = atof(argv[i]);
sum += x;
if (i == 1) {
sprintf(prefix, "%.4g", x);
} else {
sprintf(next, " + %.4g", x);
strcat(prefix, next);
printf("%s = %.4g\n", prefix, sum);
}
}
return 0;
}
运行结果:
@ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out 1e20 -1e20 3.14
1e+20 + -1e+20 = 0
1e+20 + -1e+20 + 3.14 = 3.14
@ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out -1e20 3.14
-1e+20 + 3.14 = -1e+20
@ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out -1e20 3.14 1e20
-1e+20 + 3.14 = -1e+20
-1e+20 + 3.14 + 1e+20 = 0
由此可见浮点数运算存在精度的损失,数据类型和处理方式应得到注意!
规则举例:“四舍六入五成双”。
(1)被修约的数字小于5时,该数字舍去; (2)被修约的数字大于5时,则进位;
(3)被修约的数字等于5时,要看5前面的数字,若是奇数则进位,若是偶数则将5舍掉,即修约后末尾数字都成为偶数;若5的后面还有不为“0”的任何数,则此时无论5的前面是奇数还是偶数,均应进位。
举例,用上述规则对下列数据保留3位有效数字:
9.8249=9.82, 9.82671=9.83
9.8350=9.84, 9.8351 =9.84
9.8250=9.82, 9.82501=9.83 从统计学的角度,“四舍六入五成双”比“四舍五入”要科学,在大量运算时,它使舍入后的结果误差的均值趋于零,而不是像四舍五入那样逢五就入,导致结果偏向大数,使得误差产生积累进而产生系统误差,“四舍六入五成双”使测量结果受到舍入误差的影响降到最低。
三、进制转换
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int i;
for (i = 1; i < argc; i++) {
unsigned long dig = strtoul(argv[i], NULL, 16);
putchar((char) dig);
}
putchar('\n');
return 0;
}
输入参数:30 31 32 33 34 35 36 37 38 39 输出为:0123456789。
以上完成十六进制数字序列转换为字符串。
四、存储地址
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
static void show_pointer(void *p, char *descr) {
// printf("Pointer for %s at %p\n", descr, p);
printf("%s\t%p\t%lu\n", descr, p, (unsigned long) p);
}
char big_array[1L<<24]; /* 16 MB */
//char huge_array[1L<<31]; /* 2 GB */
char huge_array[1L<<30];/* 1 GB */
int global = 0;
int useless() { return 0; }
int main ()
{
void *p1, *p2, *p3, *p4;
int local = 0;
p1 = malloc(1L << 28);
p2 = malloc(1L << 8);
//p3 = malloc(1L << 32);
p3 = malloc(1L << 16);
p4 = malloc(1L << 8);
show_pointer((void *) big_array, "big array");
show_pointer((void *) huge_array, "huge array");
show_pointer((void *) &local, "local");
show_pointer((void *) &global, "global");
show_pointer((void *) p1, "p1");
show_pointer((void *) p2, "p2");
show_pointer((void *) p3, "p3");
show_pointer((void *) p4, "p4");
show_pointer((void *) useless, "useless");
show_pointer((void *) exit, "exit");
show_pointer((void *) malloc, "malloc");
return 0;
}
运行结果:
gec@ubuntu:/mnt/hgfs/share/csapp_code$ gcc locate.c
gec@ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out
big array 0x4804a060 1208262752
huge array 0x804a060 134520928
local 0xbfcc9fdc 3217858524
global 0x804a044 134520900
p1 0xa7545008 2807320584
p2 0x49a67008 1235644424
p3 0x49a67110 1235644688
p4 0x49a77118 1235710232
useless 0x80484b6 134513846
exit 0x8048370 134513520
malloc 0x8048350 134513488
五、深度递归
#include <stdio.h>
#include <stdlib.h>
int recurse(int x) {
int a[1<<15]; /* 4 * 2^15 = 64 KiB */
printf("x = %d. a at %p\n", x, a);
a[0] = (1<<14)-1;
a[a[0]] = x-1;
if (a[a[0]] == 0)
return -1;
return recurse(a[a[0]]) - 1;
}
int main(int argc, char *argv[]) {
int x = 100;
if (argc > 1)
x = atoi(argv[1]);
int v = recurse(x);
printf("x = %d. recurse(x) = %d\n", x, v);
return 0;
}
不带参数
x = 100. a at 0xbfd3f8b0
x = 99. a at 0xbfd1f890
x = 98. a at 0xbfcff870
x = 97. a at 0xbfcdf850
x = 96. a at 0xbfcbf830
x = 95. a at 0xbfc9f810
x = 94. a at 0xbfc7f7f0
x = 93. a at 0xbfc5f7d0
x = 92. a at 0xbfc3f7b0
x = 91. a at 0xbfc1f790
x = 90. a at 0xbfbff770
x = 89. a at 0xbfbdf750
x = 88. a at 0xbfbbf730
x = 87. a at 0xbfb9f710
x = 86. a at 0xbfb7f6f0
x = 85. a at 0xbfb5f6d0
x = 84. a at 0xbfb3f6b0
x = 83. a at 0xbfb1f690
x = 82. a at 0xbfaff670
x = 81. a at 0xbfadf650
x = 80. a at 0xbfabf630
x = 79. a at 0xbfa9f610
x = 78. a at 0xbfa7f5f0
x = 77. a at 0xbfa5f5d0
x = 76. a at 0xbfa3f5b0
x = 75. a at 0xbfa1f590
x = 74. a at 0xbf9ff570
x = 73. a at 0xbf9df550
x = 72. a at 0xbf9bf530
x = 71. a at 0xbf99f510
x = 70. a at 0xbf97f4f0
x = 69. a at 0xbf95f4d0
x = 68. a at 0xbf93f4b0
x = 67. a at 0xbf91f490
x = 66. a at 0xbf8ff470
x = 65. a at 0xbf8df450
x = 64. a at 0xbf8bf430
x = 63. a at 0xbf89f410
x = 62. a at 0xbf87f3f0
x = 61. a at 0xbf85f3d0
x = 60. a at 0xbf83f3b0
x = 59. a at 0xbf81f390
x = 58. a at 0xbf7ff370
x = 57. a at 0xbf7df350
x = 56. a at 0xbf7bf330
x = 55. a at 0xbf79f310
x = 54. a at 0xbf77f2f0
x = 53. a at 0xbf75f2d0
x = 52. a at 0xbf73f2b0
x = 51. a at 0xbf71f290
x = 50. a at 0xbf6ff270
x = 49. a at 0xbf6df250
x = 48. a at 0xbf6bf230
x = 47. a at 0xbf69f210
x = 46. a at 0xbf67f1f0
x = 45. a at 0xbf65f1d0
x = 44. a at 0xbf63f1b0
x = 43. a at 0xbf61f190
x = 42. a at 0xbf5ff170
x = 41. a at 0xbf5df150
x = 40. a at 0xbf5bf130
x = 39. a at 0xbf59f110
x = 38. a at 0xbf57f0f0
输入参数如 20
x = 20. a at 0xbfb0c910
x = 19. a at 0xbfaec8f0
x = 18. a at 0xbfacc8d0
x = 17. a at 0xbfaac8b0
x = 16. a at 0xbfa8c890
x = 15. a at 0xbfa6c870
x = 14. a at 0xbfa4c850
x = 13. a at 0xbfa2c830
x = 12. a at 0xbfa0c810
x = 11. a at 0xbf9ec7f0
x = 10. a at 0xbf9cc7d0
x = 9. a at 0xbf9ac7b0
x = 8. a at 0xbf98c790
x = 7. a at 0xbf96c770
x = 6. a at 0xbf94c750
x = 5. a at 0xbf92c730
x = 4. a at 0xbf90c710
x = 3. a at 0xbf8ec6f0
x = 2. a at 0xbf8cc6d0
x = 1. a at 0xbf8ac6b0
x = 20. recurse(x) = -20
六、显示字节打印数据的字节表示:
#include <stdio.h>
/* $end show-bytes */
#include <stdlib.h>
#include <string.h>
/* $begin show-bytes */
typedef unsigned char *byte_pointer;
//typedef char *byte_pointer;
//typedef int *byte_pointer;
void show_bytes(byte_pointer start, size_t len) {
size_t i;
for (i = 0; i < len; i++)
printf("%p\t0x%.2x\n", &start[i], 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 *));
}
/* $end show-bytes */
/* $begin test-show-bytes */
void test_show_bytes(int val) {
int ival = val;
//float fval = (float) ival;
double fval = (double) ival;
int *pval = &ival;
printf("Stack variable ival = %d\n", ival);
printf("(int)ival:\n");
show_int(ival);
printf("(float)ival:\n");
show_float(fval);
printf("&ival:\n");
show_pointer(pval);
}
/* $end test-show-bytes */
void simple_show_a() {
/* $begin simple-show-a */
int val = 0x87654321;
byte_pointer valp = (byte_pointer) &val;
show_bytes(valp, 1); /* A. */
show_bytes(valp, 2); /* B. */
show_bytes(valp, 3); /* C. */
/* $end simple-show-a */
}
void simple_show_b() {
/* $begin simple-show-b */
int val = 0x12345678;
byte_pointer valp = (byte_pointer) &val;
show_bytes(valp, 1); /* A. */
show_bytes(valp, 2); /* B. */
show_bytes(valp, 3); /* C. */
/* $end simple-show-b */
}
void float_eg() {
int x = 3490593;
float f = (float) x;
printf("For x = %d\n", x);
show_int(x);
show_float(f);
x = 3510593;
f = (float) x;
printf("For x = %d\n", x);
show_int(x);
show_float(f);
}
void string_ueg() {
/* $begin show-ustring */
const char *s = "ABCDEF";
show_bytes((byte_pointer) s, strlen(s));
/* $end show-ustring */
}
void string_leg() {
/* $begin show-lstring */
const char *s = "abcdef";
show_bytes((byte_pointer) s, strlen(s));
/* $end show-lstring */
}
void show_twocomp()
{
/* $begin show-twocomp */
short x = 12345;
short mx = -x;
show_bytes((byte_pointer) &x, sizeof(short));
show_bytes((byte_pointer) &mx, sizeof(short));
/* $end show-twocomp */
}
int main(int argc, char *argv[])
{
int val = 12345;
if (argc > 1) {
val = strtol(argv[1], NULL, 0);
printf("calling test_show_bytes\n");
test_show_bytes(val);
} else {
printf("calling show_twocomp\n");
show_twocomp();
printf("Calling simple_show_a\n");
simple_show_a();
printf("Calling simple_show_b\n");
simple_show_b();
printf("Calling float_eg\n");
float_eg();
printf("Calling string_ueg\n");
string_ueg();
printf("Calling string_leg\n");
string_leg();
}
return 0;
}
不带参数的运行结果
calling show_twocomp
0xbfa18b4c 0x39
0xbfa18b4d 0x30
0xbfa18b4e 0xc7
0xbfa18b4f 0xcf
Calling simple_show_a
0xbfa18b48 0x21
0xbfa18b48 0x21
0xbfa18b49 0x43
0xbfa18b48 0x21
0xbfa18b49 0x43
0xbfa18b4a 0x65
Calling simple_show_b
0xbfa18b48 0x78
0xbfa18b48 0x78
0xbfa18b49 0x56
0xbfa18b48 0x78
0xbfa18b49 0x56
0xbfa18b4a 0x34
Calling float_eg
For x = 3490593
0xbfa18b30 0x21
0xbfa18b31 0x43
0xbfa18b32 0x35
0xbfa18b33 0x00
0xbfa18b30 0x84
0xbfa18b31 0x0c
0xbfa18b32 0x55
0xbfa18b33 0x4a
For x = 3510593
0xbfa18b30 0x41
0xbfa18b31 0x91
0xbfa18b32 0x35
0xbfa18b33 0x00
0xbfa18b30 0x04
0xbfa18b31 0x45
0xbfa18b32 0x56
0xbfa18b33 0x4a
Calling string_ueg
0x8048940 0x41
0x8048941 0x42
0x8048942 0x43
0x8048943 0x44
0x8048944 0x45
0x8048945 0x46
Calling string_leg
0x8048947 0x61
0x8048948 0x62
0x8048949 0x63
0x804894a 0x64
0x804894b 0x65
0x804894c 0x66
gec@ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out 1073741824
calling test_show_bytes
Stack variable ival = 1073741824
(int)ival:
0xbfd40020 0x00
0xbfd40021 0x00
0xbfd40022 0x00
0xbfd40023 0x40
(float)ival:
0xbfd40020 0x00
0xbfd40021 0x00
0xbfd40022 0x80
0xbfd40023 0x4e
&ival:
0xbfd40020 0x34
0xbfd40021 0x00
0xbfd40022 0xd4
0xbfd40023 0xbf
七、返回整形数据的二次方
#include <stdio.h>
#include <stdlib.h>
int sq(int x) {
return x*x;
}
int main(int argc, char *argv[]) {
int i;
for (i = 1; i < argc; i++) {
int x = atoi(argv[i]);
int sx = sq(x);
printf("sq(%d) = %d\n", x, sx);
}
return 0;
}
运行结果:
@ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out
@ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out 12
sq(12) = 144
@ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out 65535
sq(65535) = -131071
@ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out 40000
sq(40000) = 1600000000
@ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out 50000
sq(50000) = -1794967296
@ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out 400000
sq(400000) = 1086210048
@ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out 500000
sq(500000) = 891896832
出现了因数据相乘出现的溢出问题导致结果过于离谱。
下面给出相应数据范围来避免溢出的发生,同样可采用检验的方式及时发现数据异常。
整型 [signed]int -2147483648~+2147483648
无符号整型unsigned[int] 0~4294967295
短整型 short [int] -32768~32767
无符号短整型unsigned short[int] 0~65535
长整型 Long int -2147483648~+2147483648
无符号长整型unsigned [int] 0~4294967295
字符型[signed] char -128~+127
无符号字符型 unsigned char 0~255
单精度 float 3.4 x 10^(-38)~ 3.4 x 10^(+38)
双精度double 1.7 x 10^(-308)~ 1.7 x 10^(+308)
长双精度 long double 1.7 x 10^(-308)~ 1.7 x 10^(+308)
八、结构体
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int a[2];
double d;
} struct_t;
double fun(int i) {
volatile struct_t s;
s.d = 3.14;
s.a[i] = 1073741824; /* Possibly out of bounds */
return s.d; /* Should be 3.14 */
}
int main(int argc, char *argv[]) {
int i = 0;
if (argc >= 2)
i = atoi(argv[1]);
double d = fun(i);
printf("fun(%d) --> %.10f\n", i, d);
return 0;
}
结果如下:
gec@ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out 0
fun(0) --> 3.1400000000
gec@ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out 1
fun(1) --> 3.1400000000
gec@ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out 2
fun(2) --> 3.1399998665
gec@ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out 3
fun(3) --> 2.0000006104
gec@ubuntu:/mnt/hgfs/share/csapp_code$ ./a.out 4
fun(4) --> 3.1400000000
段错误 (核心已转储)
我们同样应该注意存储的溢出问题,对于结构体这种空间占用本身较大的数据类型,应设置好相应判断条件以避免各种可能发生的意外。