计算机系统基础作业

计算机系统基础

本学期我们主要学习了:
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
段错误 (核心已转储)
我们同样应该注意存储的溢出问题,对于结构体这种空间占用本身较大的数据类型,应设置好相应判断条件以避免各种可能发生的意外。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值