\n",
12 | argv[0]);
13 | exit(0);
14 | }
15 |
16 | if (inet_aton(argv[1], &addr) != 0)
17 | hostp = Gethostbyaddr((const char *)&addr, sizeof(addr), AF_INET);
18 | else
19 | hostp = Gethostbyname(argv[1]);
20 |
21 | printf("official hostname: %s\n", hostp->h_name);
22 |
23 | for (pp = hostp->h_aliases; *pp != NULL; pp++)
24 | printf("alias: %s\n", *pp);
25 |
26 | for (pp = hostp->h_addr_list; *pp != NULL; pp++) {
27 | addr.s_addr = ((struct in_addr *)*pp)->s_addr;
28 | printf("address: %s\n", inet_ntoa(addr));
29 | }
30 | exit(0);
31 | }
32 | /* $end hostinfo */
33 |
--------------------------------------------------------------------------------
/chapter11/tiny-run.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/chapter11/tiny-run.jpg
--------------------------------------------------------------------------------
/chapter11/tiny-run2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/chapter11/tiny-run2.jpg
--------------------------------------------------------------------------------
/chapter11/tiny/cgi-bin/adder:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/chapter11/tiny/cgi-bin/adder
--------------------------------------------------------------------------------
/chapter11/tiny/cgi-bin/adder.c:
--------------------------------------------------------------------------------
1 | /*
2 | * adder.c - a minimal CGI program that adds two numbers together
3 | */
4 | #include "csapp.h"
5 |
6 | int main(void) {
7 | char *buf, *p;
8 | char arg1[MAXLINE], arg2[MAXLINE], content[MAXLINE];
9 | int n1=0, n2=0;
10 |
11 | /* Extract the two arguments */
12 | if ((buf = getenv("QUERY_STRING")) != NULL) {
13 | p = strchr(buf, '&');
14 | *p = '\0';
15 | strcpy(arg1, buf);
16 | strcpy(arg2, p+1);
17 | n1 = atoi(arg1);
18 | n2 = atoi(arg2);
19 | }
20 |
21 | /* Make the response body */
22 | sprintf(content, "Welcome to add.com: ");
23 | sprintf(content, "%sTHE Internet addition portal.\r\n", content);
24 | sprintf(content, "%sThe answer is: %d + %d = %d\r\n
",
25 | content, n1, n2, n1 + n2);
26 | sprintf(content, "%sThanks for visiting!\r\n", content);
27 |
28 | /* Generate the HTTP response */
29 | printf("Content-length: %d\r\n", (int)strlen(content));
30 | printf("Content-type: text/html\r\n\r\n");
31 | printf("%s", content);
32 | fflush(stdout);
33 | exit(0);
34 | }
35 |
--------------------------------------------------------------------------------
/chapter11/tiny/public_html/hello.txt:
--------------------------------------------------------------------------------
1 | Hello Vonzhou!
2 |
3 | --from tiny server
--------------------------------------------------------------------------------
/chapter11/tiny/tiny:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/chapter11/tiny/tiny
--------------------------------------------------------------------------------
/chapter8/README.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | gcc -shared -fPIC -I../include -o csapp.so csapp.c
15 |
16 |
17 | gcc fork.c -I../include ./csapp.so -lpthread
18 |
19 |
20 | fork分别执行1,2,3次的效果分析:
21 | vi fork1.c
22 | gcc fork1.c -I../include ./csapp.so -lpthread
23 | ./a.out
24 | ppid=3276PeepOpenid=6143
25 | ppid=6143PeepOpenid=6144
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/chapter8/alarm.c:
--------------------------------------------------------------------------------
1 | /* $begin alarm */
2 | #include "csapp.h"
3 |
4 | void handler(int sig)
5 | {
6 | static int beeps = 0;
7 |
8 | printf("BEEP\n");
9 | if (++beeps < 5)
10 | Alarm(1); /* Next SIGALRM will be delivered in 1 second */
11 | else {
12 | printf("BOOM!\n");
13 | exit(0);
14 | }
15 | }
16 |
17 | int main()
18 | {
19 | Signal(SIGALRM, handler); /* install SIGALRM handler */
20 | Alarm(1); /* Next SIGALRM will be delivered in 1s */
21 |
22 | while (1) {
23 | ; /* Signal handler returns control here each time */
24 | }
25 | exit(0);
26 | }
27 | /* $end alarm */
28 |
--------------------------------------------------------------------------------
/chapter8/counterprob.c:
--------------------------------------------------------------------------------
1 | /* $begin counterprob */
2 | #include "csapp.h"
3 |
4 | int counter = 0;
5 |
6 | void handler(int sig)
7 | {
8 | counter++;
9 | sleep(1); /* Do some work in the handler */
10 | return;
11 | }
12 |
13 | int main()
14 | {
15 | int i;
16 |
17 | Signal(SIGUSR2, handler);
18 |
19 | if (Fork() == 0) { /* Child */
20 | for (i = 0; i < 5; i++) {
21 | Kill(getppid(), SIGUSR2);
22 | printf("sent SIGUSR2 to parent\n");
23 | }
24 | exit(0);
25 | }
26 |
27 | Wait(NULL);
28 | printf("counter=%d\n", counter);
29 | exit(0);
30 | }
31 | /* $end counterprob */
32 |
--------------------------------------------------------------------------------
/chapter8/fork.c:
--------------------------------------------------------------------------------
1 | #include "csapp.h"
2 |
3 | int main()
4 | {
5 | pid_t pid;
6 | int x = 1;
7 |
8 | pid = Fork();
9 | if (pid == 0) { /* Child */
10 | printf("child,pid=%d : x=%d\n",getpid(), ++x);
11 | exit(0);
12 | }
13 |
14 | /* Parent */
15 | printf("parent,pid=%d: x=%d\n",getpid(), --x);
16 | exit(0);
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/chapter8/fork1.c:
--------------------------------------------------------------------------------
1 | #include "csapp.h"
2 |
3 | int main()
4 | {
5 | Fork();
6 | printf("ppid=%d,pid=%d\n", getppid(), getpid());
7 | exit(0);
8 | }
9 |
10 |
--------------------------------------------------------------------------------
/chapter8/forkprob0.c:
--------------------------------------------------------------------------------
1 | #include "csapp.h"
2 |
3 | int main()
4 | {
5 | int x = 1;
6 |
7 | if (Fork() == 0)
8 | printf("printf1: x=%d\n", ++x);
9 | printf("printf2: x=%d\n", --x);
10 | exit(0);
11 | }
12 |
--------------------------------------------------------------------------------
/chapter8/forkprob1.c:
--------------------------------------------------------------------------------
1 | /* $begin forkprob1 */
2 | #include "csapp.h"
3 |
4 | int main()
5 | {
6 | int i;
7 |
8 | for (i = 0; i < 2; i++)
9 | Fork();
10 | printf("hello\n");
11 | exit(0);
12 | }
13 | /* $end forkprob1 */
14 |
--------------------------------------------------------------------------------
/chapter8/forkprob2.c:
--------------------------------------------------------------------------------
1 | /* $begin forkprob2 */
2 | #include "csapp.h"
3 |
4 | void end(void)
5 | {
6 | printf("2");
7 | }
8 |
9 | int main()
10 | {
11 | if (Fork() == 0)
12 | atexit(end);
13 | if (Fork() == 0)
14 | printf("0");
15 | else
16 | printf("1");
17 | exit(0);
18 | }
19 | /* $end forkprob2 */
20 |
21 |
--------------------------------------------------------------------------------
/chapter8/forkprob3.c:
--------------------------------------------------------------------------------
1 | /* $begin forkprob3 */
2 | #include "csapp.h"
3 |
4 | int main()
5 | {
6 | int x = 3;
7 |
8 | if (Fork() != 0)
9 | printf("x=%d\n", ++x);
10 |
11 | printf("x=%d\n", --x);
12 | exit(0);
13 | }
14 | /* $end forkprob3 */
15 |
16 |
--------------------------------------------------------------------------------
/chapter8/forkprob4.c:
--------------------------------------------------------------------------------
1 | /* $begin forkprob4 */
2 | #include "csapp.h"
3 |
4 | void doit()
5 | {
6 | Fork();
7 | Fork();
8 | printf("hello\n");
9 | return;
10 | }
11 |
12 | int main()
13 | {
14 | doit();
15 | printf("hello\n");
16 | exit(0);
17 | }
18 | /* $end forkprob4 */
19 |
20 |
21 |
--------------------------------------------------------------------------------
/chapter8/forkprob5.c:
--------------------------------------------------------------------------------
1 | /* $begin forkprob5 */
2 | #include "csapp.h"
3 |
4 | void doit()
5 | {
6 | if (Fork() == 0) {
7 | Fork();
8 | printf("hello\n");
9 | exit(0);
10 | }
11 | return;
12 | }
13 |
14 | int main()
15 | {
16 | doit();
17 | printf("hello\n");
18 | exit(0);
19 | }
20 | /* $end forkprob5 */
21 |
--------------------------------------------------------------------------------
/chapter8/forkprob6.c:
--------------------------------------------------------------------------------
1 | /* $begin forkprob6 */
2 | #include "csapp.h"
3 |
4 | void doit()
5 | {
6 | if (Fork() == 0) {
7 | Fork();
8 | printf("hello\n");
9 | return;
10 | }
11 | return;
12 | }
13 |
14 | int main()
15 | {
16 | doit();
17 | printf("hello\n");
18 | exit(0);
19 | }
20 | /* $end forkprob6 */
21 |
--------------------------------------------------------------------------------
/chapter8/forkprob7.c:
--------------------------------------------------------------------------------
1 | /* $begin forkprob7 */
2 | #include "csapp.h"
3 | int counter = 1;
4 |
5 | int main()
6 | {
7 | if (fork() == 0) {
8 | counter--;
9 | exit(0);
10 | }
11 | else {
12 | Wait(NULL);
13 | printf("counter = %d\n", ++counter);
14 | }
15 | exit(0);
16 | }
17 | /* $end forkprob7 */
18 |
--------------------------------------------------------------------------------
/chapter8/forkprob8.c:
--------------------------------------------------------------------------------
1 | #include "csapp.h"
2 |
3 | /* $begin forkprob8 */
4 | void foo(int n)
5 | {
6 | int i;
7 |
8 | for (i = 0; i < n; i++)
9 | Fork();
10 | printf("hello\n");
11 | exit(0);
12 | }
13 | /* $end forkprob8 */
14 |
15 | int main(int argc, char **argv)
16 | {
17 | if (argc < 2) {
18 | printf("usage: %s \n", argv[0]);
19 | exit(0);
20 | }
21 | foo(atoi(argv[1]));
22 | exit(0);
23 | }
24 |
--------------------------------------------------------------------------------
/chapter8/hello:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/chapter8/hello
--------------------------------------------------------------------------------
/chapter8/hello-asm.sa:
--------------------------------------------------------------------------------
1 | .section .data
2 | string:
3 | .ascii "hello, world\n"
4 | string_end:
5 | .equ len, string_end - string
6 | #.equ symbol,expression 设置symbol的值为expression
7 |
8 | .section .text
9 | .globl main
10 | main:
11 | # First, call write(1, "hello, world\n", 13)
12 | movl $4, %eax # write的系统调用号是 4
13 | movl $1, %ebx # stdout has descriptor 1
14 | movl $string, %ecx # Hello world string
15 | movl $len, %edx # String length
16 | int $0x80 # System call code
17 |
18 | # Next, call exit(0)
19 | movl $1, %eax # System call number 0
20 | movl $0, %ebx # Argument is 0
21 | int $0x80 # System call code
22 |
--------------------------------------------------------------------------------
/chapter8/kill.c:
--------------------------------------------------------------------------------
1 | /* $begin kill */
2 | #include "csapp.h"
3 |
4 | int main()
5 | {
6 | pid_t pid;
7 |
8 | /* Child sleeps until SIGKILL signal received, then dies */
9 | if ((pid = Fork()) == 0) {
10 | Pause(); /* Wait for a signal to arrive */
11 | printf("control should never reach here!\n");
12 | exit(0);
13 | }
14 |
15 | /* Parent sends a SIGKILL signal to a child */
16 | Kill(pid, SIGKILL);
17 | exit(0);
18 | }
19 | /* $end kill */
20 |
--------------------------------------------------------------------------------
/chapter8/procmask1.c:
--------------------------------------------------------------------------------
1 | #include "csapp.h"
2 |
3 | void initjobs()
4 | {
5 | }
6 |
7 | void addjob(int pid)
8 | {
9 | }
10 |
11 | void deletejob(int pid)
12 | {
13 | }
14 |
15 | /* $begin procmask1 */
16 | void handler(int sig)
17 | {
18 | pid_t pid;
19 | while ((pid = waitpid(-1, NULL, 0)) > 0) /* Reap a zombie child */
20 | deletejob(pid); /* Delete the child from the job list */
21 | if (errno != ECHILD)
22 | unix_error("waitpid error");
23 | }
24 |
25 | int main(int argc, char **argv)
26 | {
27 | int pid;
28 |
29 | Signal(SIGCHLD, handler);
30 | initjobs(); /* Initialize the job list */
31 |
32 | while (1) {
33 | /* Child process */
34 | if ((pid = Fork()) == 0) {
35 | Execve("/bin/date", argv, NULL);
36 | }
37 |
38 | /* Parent process */
39 | addjob(pid); /* Add the child to the job list */
40 | }
41 | exit(0);
42 | }
43 | /* $end procmask1 */
44 |
--------------------------------------------------------------------------------
/chapter8/procmask2.c:
--------------------------------------------------------------------------------
1 | #include "csapp.h"
2 |
3 | void initjobs()
4 | {
5 | }
6 |
7 | void addjob(int pid)
8 | {
9 | }
10 |
11 | void deletejob(int pid)
12 | {
13 | }
14 |
15 | /* $begin procmask2 */
16 | void handler(int sig)
17 | {
18 | pid_t pid;
19 | while ((pid = waitpid(-1, NULL, 0)) > 0) /* Reap a zombie child */
20 | deletejob(pid); /* Delete the child from the job list */
21 | if (errno != ECHILD)
22 | unix_error("waitpid error");
23 | }
24 |
25 | int main(int argc, char **argv)
26 | {
27 | int pid;
28 | sigset_t mask;
29 |
30 | Signal(SIGCHLD, handler);
31 | initjobs(); /* Initialize the job list */
32 |
33 | while (1) {
34 | Sigemptyset(&mask);
35 | Sigaddset(&mask, SIGCHLD);
36 | Sigprocmask(SIG_BLOCK, &mask, NULL); /* Block SIGCHLD */
37 |
38 | /* Child process */
39 | if ((pid = Fork()) == 0) {
40 | Sigprocmask(SIG_UNBLOCK, &mask, NULL); /* Unblock SIGCHLD */
41 | Execve("/bin/date", argv, NULL);
42 | }
43 |
44 | /* Parent process */
45 | addjob(pid); /* Add the child to the job list */
46 | Sigprocmask(SIG_UNBLOCK, &mask, NULL); /* Unblock SIGCHLD */
47 | }
48 | exit(0);
49 | }
50 | /* $end procmask2 */
51 |
--------------------------------------------------------------------------------
/chapter8/restart.c:
--------------------------------------------------------------------------------
1 | /* $begin restart */
2 | #include "csapp.h"
3 |
4 | sigjmp_buf buf;
5 |
6 | void handler(int sig)
7 | {
8 | siglongjmp(buf, 1);
9 | }
10 |
11 | int main()
12 | {
13 | Signal(SIGINT, handler);
14 |
15 | if (!sigsetjmp(buf, 1))
16 | printf("starting\n");
17 | else
18 | printf("restarting\n");
19 |
20 | while(1) {
21 | Sleep(1);
22 | printf("processing...\n");
23 | }
24 | exit(0);
25 | }
26 | /* $end restart */
27 |
--------------------------------------------------------------------------------
/chapter8/setjmp.c:
--------------------------------------------------------------------------------
1 | /* $begin setjmp */
2 | #include "csapp.h"
3 |
4 | jmp_buf buf;
5 |
6 | int error1 = 0;
7 | int error2 = 1;
8 |
9 | void foo(void), bar(void);
10 |
11 | int main()
12 | {
13 | int rc;
14 |
15 | rc = setjmp(buf);
16 | if (rc == 0)
17 | foo();
18 | else if (rc == 1)
19 | printf("Detected an error1 condition in foo\n");
20 | else if (rc == 2)
21 | printf("Detected an error2 condition in foo\n");
22 | else
23 | printf("Unknown error condition in foo\n");
24 | exit(0);
25 | }
26 |
27 | /* Deeply nested function foo */
28 | void foo(void)
29 | {
30 | if (error1)
31 | longjmp(buf, 1);
32 | bar();
33 | }
34 |
35 | void bar(void)
36 | {
37 | if (error2)
38 | longjmp(buf, 2);
39 | }
40 | /* $end setjmp */
41 |
--------------------------------------------------------------------------------
/chapter8/sigint1.c:
--------------------------------------------------------------------------------
1 | /* $begin sigint1 */
2 | #include "csapp.h"
3 |
4 | void handler(int sig) /* SIGINT handler */ //line:ecf:sigint1:beginhandler
5 | {
6 | printf("Caught SIGINT\n"); //line:ecf:sigint1:printhandler
7 | exit(0); //line:ecf:sigint1:exithandler
8 | } //line:ecf:sigint1:endhandler
9 |
10 | int main()
11 | {
12 | /* Install the SIGINT handler */
13 | if (signal(SIGINT, handler) == SIG_ERR) //line:ecf:sigint1:begininstall
14 | unix_error("signal error"); //line:ecf:sigint1:endinstall
15 |
16 | pause(); /* Wait for the receipt of a signal */ //line:ecf:sigint1:pause
17 |
18 | exit(0);
19 | }
20 | /* $end sigint1 */
21 |
--------------------------------------------------------------------------------
/chapter8/signal1.c:
--------------------------------------------------------------------------------
1 | /* $begin signal1 */
2 | #include "csapp.h"
3 |
4 | void handler1(int sig)
5 | {
6 | pid_t pid;
7 |
8 | if ((pid = waitpid(-1, NULL, 0)) < 0)
9 | unix_error("waitpid error");
10 | printf("Handler reaped child %d\n", (int)pid);
11 | Sleep(2);
12 | return;
13 | }
14 |
15 | int main()
16 | {
17 | int i, n;
18 | char buf[MAXBUF];
19 |
20 | if (signal(SIGCHLD, handler1) == SIG_ERR)
21 | unix_error("signal error");
22 |
23 | /* Parent creates children */
24 | for (i = 0; i < 3; i++) {
25 | if (Fork() == 0) {
26 | printf("Hello from child %d\n", (int)getpid());
27 | Sleep(1);
28 | exit(0);
29 | }
30 | }
31 |
32 | /* Parent waits for terminal input and then processes it */
33 | if ((n = read(STDIN_FILENO, buf, sizeof(buf))) < 0)
34 | unix_error("read");
35 |
36 | printf("Parent processing input\n");
37 | while (1)
38 | ;
39 |
40 | exit(0);
41 | }
42 | /* $end signal1 */
43 |
--------------------------------------------------------------------------------
/chapter8/signal2.c:
--------------------------------------------------------------------------------
1 | /* $begin signal2 */
2 | #include "csapp.h"
3 |
4 | void handler2(int sig)
5 | {
6 | pid_t pid;
7 |
8 | while ((pid = waitpid(-1, NULL, 0)) > 0)
9 | printf("Handler reaped child %d\n", (int)pid);
10 | if (errno != ECHILD)
11 | unix_error("waitpid error");
12 | Sleep(2);
13 | return;
14 | }
15 |
16 | int main()
17 | {
18 | int i, n;
19 | char buf[MAXBUF];
20 |
21 | if (signal(SIGCHLD, handler2) == SIG_ERR)
22 | unix_error("signal error");
23 |
24 | /* Parent creates children */
25 | for (i = 0; i < 3; i++) {
26 | if (Fork() == 0) {
27 | printf("Hello from child %d\n", (int)getpid());
28 | Sleep(1);
29 | exit(0);
30 | }
31 | }
32 |
33 | /* Parent waits for terminal input and then processes it */
34 | if ((n = read(STDIN_FILENO, buf, sizeof(buf))) < 0)
35 | unix_error("read error");
36 |
37 | printf("Parent processing input\n");
38 | while (1)
39 | ;
40 |
41 | exit(0);
42 | }
43 | /* $end signal2 */
44 |
--------------------------------------------------------------------------------
/chapter8/signal3.c:
--------------------------------------------------------------------------------
1 | /* $begin signal3 */
2 | #include "csapp.h"
3 |
4 | void handler2(int sig)
5 | {
6 | pid_t pid;
7 |
8 | while ((pid = waitpid(-1, NULL, 0)) > 0)
9 | printf("Handler reaped child %d\n", (int)pid);
10 | if (errno != ECHILD)
11 | unix_error("waitpid error");
12 | Sleep(2);
13 | return;
14 | }
15 |
16 | int main() {
17 | int i, n;
18 | char buf[MAXBUF];
19 | pid_t pid;
20 |
21 | if (signal(SIGCHLD, handler2) == SIG_ERR)
22 | unix_error("signal error");
23 |
24 | /* Parent creates children */
25 | for (i = 0; i < 3; i++) {
26 | pid = Fork();
27 | if (pid == 0) {
28 | printf("Hello from child %d\n", (int)getpid());
29 | Sleep(1);
30 | exit(0);
31 | }
32 | }
33 |
34 | /* Manually restart the read call if it is interrupted */
35 | while ((n = read(STDIN_FILENO, buf, sizeof(buf))) < 0)
36 | if (errno != EINTR)
37 | unix_error("read error");
38 |
39 | printf("Parent processing input\n");
40 | while (1)
41 | ;
42 |
43 | exit(0);
44 | }
45 | /* $end signal3 */
46 |
--------------------------------------------------------------------------------
/chapter8/signal4.c:
--------------------------------------------------------------------------------
1 | /* $begin signal4 */
2 | #include "csapp.h"
3 |
4 | void handler2(int sig)
5 | {
6 | pid_t pid;
7 |
8 | while ((pid = waitpid(-1, NULL, 0)) > 0)
9 | printf("Handler reaped child %d\n", (int)pid);
10 | if (errno != ECHILD)
11 | unix_error("waitpid error");
12 | Sleep(2);
13 | return;
14 | }
15 |
16 | int main()
17 | {
18 | int i, n;
19 | char buf[MAXBUF];
20 | pid_t pid;
21 |
22 | Signal(SIGCHLD, handler2); /* sigaction error-handling wrapper */
23 |
24 | /* Parent creates children */
25 | for (i = 0; i < 3; i++) {
26 | pid = Fork();
27 | if (pid == 0) {
28 | printf("Hello from child %d\n", (int)getpid());
29 | Sleep(1);
30 | exit(0);
31 | }
32 | }
33 |
34 | /* Parent waits for terminal input and then processes it */
35 | if ((n = read(STDIN_FILENO, buf, sizeof(buf))) < 0)
36 | unix_error("read error");
37 |
38 | printf("Parent processing input\n");
39 | while (1)
40 | ;
41 | exit(0);
42 | }
43 | /* $end signal4 */
44 |
--------------------------------------------------------------------------------
/chapter8/signalprob0.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | /* $begin signalprob0 */
8 | pid_t pid;
9 | int counter = 2;
10 |
11 | void handler1(int sig) {
12 | counter = counter - 1;
13 | printf("%d", counter);
14 | fflush(stdout);
15 | exit(0);
16 | }
17 |
18 | int main() {
19 | signal(SIGUSR1, handler1);
20 |
21 | printf("%d", counter);
22 | fflush(stdout);
23 |
24 | if ((pid = fork()) == 0) {
25 | while(1) {};
26 | }
27 | kill(pid, SIGUSR1);
28 | waitpid(-1, NULL, 0);
29 | counter = counter + 1;
30 | printf("%d", counter);
31 | exit(0);
32 | }
33 | /* $end signalprob0 */
34 |
--------------------------------------------------------------------------------
/chapter8/waitpid1.c:
--------------------------------------------------------------------------------
1 | /* $begin waitpid1 */
2 | #include "csapp.h"
3 | #define N 2
4 |
5 | int main()
6 | {
7 | int status, i;
8 | pid_t pid;
9 |
10 | /* Parent creates N children */
11 | for (i = 0; i < N; i++) //line:ecf:waitpid1:for
12 | if ((pid = Fork()) == 0) /* child */ //line:ecf:waitpid1:fork
13 | exit(100+i); //line:ecf:waitpid1:exit
14 |
15 | /* Parent reaps N children in no particular order */
16 | while ((pid = waitpid(-1, &status, 0)) > 0) { //line:ecf:waitpid1:waitpid
17 | if (WIFEXITED(status)) //line:ecf:waitpid1:wifexited
18 | printf("child %d terminated normally with exit status=%d\n",
19 | pid, WEXITSTATUS(status)); //line:ecf:waitpid1:wexitstatus
20 | else
21 | printf("child %d terminated abnormally\n", pid);
22 | }
23 |
24 | /* The only normal termination is if there are no more children */
25 | if (errno != ECHILD) //line:ecf:waitpid1:errno
26 | unix_error("waitpid error");
27 |
28 | exit(0);
29 | }
30 | /* $end waitpid1 */
31 |
--------------------------------------------------------------------------------
/chapter8/waitpid2.c:
--------------------------------------------------------------------------------
1 | /* $begin waitpid2 */
2 | #include "csapp.h"
3 | #define N 2
4 |
5 | int main()
6 | {
7 | int status, i;
8 | pid_t pid[N], retpid;
9 |
10 | /* Parent creates N children */
11 | for (i = 0; i < N; i++)
12 | if ((pid[i] = Fork()) == 0) /* Child */ //line:ecf:waitpid2:fork
13 | exit(100+i);
14 |
15 | /* Parent reaps N children in order */
16 | i = 0;
17 | while ((retpid = waitpid(pid[i++], &status, 0)) > 0) { //line:ecf:waitpid2:waitpid
18 | if (WIFEXITED(status))
19 | printf("child %d terminated normally with exit status=%d\n",
20 | retpid, WEXITSTATUS(status));
21 | else
22 | printf("child %d terminated abnormally\n", retpid);
23 | }
24 |
25 | /* The only normal termination is if there are no more children */
26 | if (errno != ECHILD)
27 | unix_error("waitpid error");
28 |
29 | exit(0);
30 | }
31 | /* $end waitpid2 */
32 |
--------------------------------------------------------------------------------
/chapter8/waitprob0.c:
--------------------------------------------------------------------------------
1 | #include "csapp.h"
2 |
3 | /* $begin waitprob0 */
4 | int main()
5 | {
6 | if (Fork() == 0) {
7 | printf("a");
8 | }
9 | else {
10 | printf("b");
11 | waitpid(-1, NULL, 0);
12 | }
13 | printf("c");
14 | exit(0);
15 | }
16 | /* $end waitprob0 */
17 |
--------------------------------------------------------------------------------
/chapter8/waitprob1.c:
--------------------------------------------------------------------------------
1 | #include "csapp.h"
2 |
3 | /* $begin waitprob1 */
4 | int main()
5 | {
6 | int status;
7 | pid_t pid;
8 |
9 | printf("Hello\n");
10 | pid = Fork();
11 | printf("%d\n", !pid);
12 | if (pid != 0) {
13 | if (waitpid(-1, &status, 0) > 0) {
14 | if (WIFEXITED(status) != 0)
15 | printf("%d\n", WEXITSTATUS(status));
16 | }
17 | }
18 | printf("Bye\n");
19 | exit(2);
20 | }
21 | /* $end waitprob1 */
22 |
--------------------------------------------------------------------------------
/chapter8/waitprob3.c:
--------------------------------------------------------------------------------
1 | #include "csapp.h"
2 |
3 | /* $begin waitprob3 */
4 | int main()
5 | {
6 | if (fork() == 0) {
7 | printf("a");
8 | exit(0);
9 | }
10 | else {
11 | printf("b");
12 | waitpid(-1, NULL, 0);
13 | }
14 | printf("c");
15 | exit(0);
16 | }
17 | /* $end waitprob3 */
18 |
--------------------------------------------------------------------------------
/code/conc/ctime_ts.c:
--------------------------------------------------------------------------------
1 | /*
2 | * ctime_ts - A thread-safe wrapper for ctime
3 | */
4 | #include "csapp.h"
5 | #define MAXSTR 128
6 |
7 | static sem_t mutex; /* protects calls to ctime */
8 |
9 | static void init_ctime_ts(void)
10 | {
11 | Sem_init(&mutex, 0, 1);
12 | }
13 |
14 | /* $begin ctime_ts */
15 | char *ctime_ts(const time_t *timep, char *privatep)
16 | {
17 | char *sharedp;
18 |
19 | P(&mutex);
20 | sharedp = ctime(timep);
21 | strcpy(privatep, sharedp); /* Copy string from shared to private */
22 | V(&mutex);
23 | return privatep;
24 | }
25 | /* $end ctime_ts */
26 |
27 | int main()
28 | {
29 | char timestr[MAXSTR];
30 | time_t timeval;
31 |
32 | /* Thread-safe code to print the current time string */
33 | init_ctime_ts();
34 | timeval = time(NULL);
35 | ctime_ts(&timeval, timestr);
36 | printf("%s", timestr);
37 | exit(0);
38 | }
39 |
--------------------------------------------------------------------------------
/code/conc/echo_cnt.c:
--------------------------------------------------------------------------------
1 | /*
2 | * A thread-safe version of echo that counts the total number
3 | * of bytes received from clients.
4 | */
5 | /* $begin echo_cnt */
6 | #include "csapp.h"
7 |
8 | static int byte_cnt; /* byte counter */
9 | static sem_t mutex; /* and the mutex that protects it */
10 |
11 | static void init_echo_cnt(void)
12 | {
13 | Sem_init(&mutex, 0, 1);
14 | byte_cnt = 0;
15 | }
16 |
17 | void echo_cnt(int connfd)
18 | {
19 | int n;
20 | char buf[MAXLINE];
21 | rio_t rio;
22 | static pthread_once_t once = PTHREAD_ONCE_INIT;
23 |
24 | Pthread_once(&once, init_echo_cnt); //line:conc:pre:pthreadonce
25 | Rio_readinitb(&rio, connfd); //line:conc:pre:rioinitb
26 | while((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0) {
27 | P(&mutex);
28 | byte_cnt += n; //line:conc:pre:cntaccess1
29 | printf("thread %d received %d (%d total) bytes on fd %d\n",
30 | (int) pthread_self(), n, byte_cnt, connfd); //line:conc:pre:cntaccess2
31 | V(&mutex);
32 | Rio_writen(connfd, buf, n);
33 | }
34 | }
35 | /* $end echo_cnt */
36 |
37 |
--------------------------------------------------------------------------------
/code/conc/hello.c:
--------------------------------------------------------------------------------
1 | /*
2 | * hello.c - Pthreads "hello, world" program
3 | */
4 | /* $begin hello */
5 | #include "csapp.h"
6 | void *thread(void *vargp); //line:conc:hello:prototype
7 |
8 | int main() //line:conc:hello:main
9 | {
10 | pthread_t tid; //line:conc:hello:tid
11 | Pthread_create(&tid, NULL, thread, NULL); //line:conc:hello:create
12 | Pthread_join(tid, NULL); //line:conc:hello:join
13 | exit(0); //line:conc:hello:exit
14 | }
15 |
16 | void *thread(void *vargp) /* thread routine */ //line:conc:hello:beginthread
17 | {
18 | printf("Hello, world!\n");
19 | return NULL; //line:conc:hello:return
20 | } //line:conc:hello:endthread
21 | /* $end hello */
22 |
--------------------------------------------------------------------------------
/code/conc/hellobug.c:
--------------------------------------------------------------------------------
1 | /*
2 | * hellobug.c - "hello, world" program with a bug
3 | */
4 | /* $begin hellobug */
5 | #include "csapp.h"
6 | void *thread(void *vargp);
7 |
8 | int main()
9 | {
10 | pthread_t tid;
11 |
12 | Pthread_create(&tid, NULL, thread, NULL);
13 | exit(0);
14 | }
15 |
16 | /* thread routine */
17 | void *thread(void *vargp)
18 | {
19 | Sleep(1);
20 | printf("Hello, world!\n");
21 | return NULL;
22 | }
23 | /* $end hellobug */
24 |
--------------------------------------------------------------------------------
/code/conc/norace.c:
--------------------------------------------------------------------------------
1 | /*
2 | * norace.c - fixes the race in race.c
3 | */
4 | /* $begin norace */
5 | #include "csapp.h"
6 | #define N 4
7 |
8 | void *thread(void *vargp);
9 |
10 | int main()
11 | {
12 | pthread_t tid[N];
13 | int i, *ptr;
14 |
15 | for (i = 0; i < N; i++) {
16 | ptr = Malloc(sizeof(int)); //line:conc:norace:createthread1
17 | *ptr = i; //line:conc:norace:createthread2
18 | Pthread_create(&tid[i], NULL, thread, ptr); //line:conc:norace:createthread3
19 | } //line:conc:norace:endloop
20 | for (i = 0; i < N; i++)
21 | Pthread_join(tid[i], NULL);
22 | exit(0);
23 | }
24 |
25 | /* thread routine */
26 | void *thread(void *vargp)
27 | {
28 | int myid = *((int *)vargp);
29 | Free(vargp);
30 | printf("Hello from thread %d\n", myid);
31 | return NULL;
32 | }
33 | /* $end norace */
34 |
--------------------------------------------------------------------------------
/code/conc/race.c:
--------------------------------------------------------------------------------
1 | /*
2 | * race.c - demonstrates a race condition
3 | */
4 | /* $begin race */
5 | #include "csapp.h"
6 | #define N 4
7 |
8 | void *thread(void *vargp);
9 |
10 | int main()
11 | {
12 | pthread_t tid[N];
13 | int i;
14 |
15 | for (i = 0; i < N; i++)
16 | Pthread_create(&tid[i], NULL, thread, &i); //line:conc:race:createthread
17 | for (i = 0; i < N; i++)
18 | Pthread_join(tid[i], NULL);
19 | exit(0);
20 | }
21 |
22 | /* thread routine */
23 | void *thread(void *vargp)
24 | {
25 | int myid = *((int *)vargp); //line:conc:race:derefarg
26 | printf("Hello from thread %d\n", myid);
27 | return NULL;
28 | }
29 | /* $end race */
30 |
--------------------------------------------------------------------------------
/code/conc/rand.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | /* $begin rand */
5 | unsigned int next = 1;
6 |
7 | /* rand - return pseudo-random integer on 0..32767 */
8 | int rand(void)
9 | {
10 | next = next*1103515245 + 12345;
11 | return (unsigned int)(next/65536) % 32768;
12 | }
13 |
14 | /* srand - set seed for rand() */
15 | void srand(unsigned int seed)
16 | {
17 | next = seed;
18 | }
19 | /* $end rand */
20 |
21 | int main()
22 | {
23 | srand(100);
24 | printf("%d\n", rand());
25 | printf("%d\n", rand());
26 | printf("%d\n", rand());
27 | exit(0);
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/code/conc/rand_r.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | /* $begin rand_r */
5 | /* rand_r - a reentrant pseudo-random integer on 0..32767 */
6 | int rand_r(unsigned int *nextp)
7 | {
8 | *nextp = *nextp * 1103515245 + 12345;
9 | return (unsigned int)(*nextp / 65536) % 32768;
10 | }
11 | /* $end rand_r */
12 |
13 | int main()
14 | {
15 | unsigned int next = 1;
16 |
17 | printf("%d\n", rand_r(&next));
18 | printf("%d\n", rand_r(&next));
19 | printf("%d\n", rand_r(&next));
20 | exit(0);
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/code/conc/sbuf.h:
--------------------------------------------------------------------------------
1 | #ifndef __SBUF_H__
2 | #define __SBUF_H__
3 |
4 | #include "csapp.h"
5 |
6 | /* $begin sbuft */
7 | typedef struct {
8 | int *buf; /* Buffer array */
9 | int n; /* Maximum number of slots */
10 | int front; /* buf[(front+1)%n] is first item */
11 | int rear; /* buf[rear%n] is last item */
12 | sem_t mutex; /* Protects accesses to buf */
13 | sem_t slots; /* Counts available slots */
14 | sem_t items; /* Counts available items */
15 | } sbuf_t;
16 | /* $end sbuft */
17 |
18 | void sbuf_init(sbuf_t *sp, int n);
19 | void sbuf_deinit(sbuf_t *sp);
20 | void sbuf_insert(sbuf_t *sp, int item);
21 | int sbuf_remove(sbuf_t *sp);
22 |
23 | #endif /* __SBUF_H__ */
24 |
--------------------------------------------------------------------------------
/code/conc/sharing.c:
--------------------------------------------------------------------------------
1 | /* $begin sharing */
2 | #include "csapp.h"
3 | #define N 2
4 | void *thread(void *vargp);
5 |
6 | char **ptr; /* global variable */ //line:conc:sharing:ptrdec
7 |
8 | int main()
9 | {
10 | int i;
11 | pthread_t tid;
12 | char *msgs[N] = {
13 | "Hello from foo",
14 | "Hello from bar"
15 | };
16 |
17 | ptr = msgs;
18 | for (i = 0; i < N; i++)
19 | Pthread_create(&tid, NULL, thread, (void *)i);
20 | Pthread_exit(NULL);
21 | }
22 |
23 | void *thread(void *vargp)
24 | {
25 | int myid = (int)vargp;
26 | static int cnt = 0; //line:conc:sharing:cntdec
27 | printf("[%d]: %s (cnt=%d)\n", myid, ptr[myid], ++cnt); //line:conc:sharing:stack
28 | return NULL;
29 | }
30 | /* $end sharing */
31 |
--------------------------------------------------------------------------------
/code/conc/tfgets-main.c:
--------------------------------------------------------------------------------
1 | /* $begin tfgetsmain */
2 | #include "csapp.h"
3 |
4 | char *tfgets(char *s, int size, FILE *stream);
5 |
6 | int main()
7 | {
8 | char buf[MAXLINE];
9 |
10 | if (tfgets(buf, MAXLINE, stdin) == NULL)
11 | printf("BOOM!\n");
12 | else
13 | printf("%s", buf);
14 |
15 | exit(0);
16 | }
17 | /* $end tfgetsmain */
18 |
--------------------------------------------------------------------------------
/code/ecf/alarm.c:
--------------------------------------------------------------------------------
1 | /* $begin alarm */
2 | #include "csapp.h"
3 |
4 | void handler(int sig)
5 | {
6 | static int beeps = 0;
7 |
8 | printf("BEEP\n");
9 | if (++beeps < 5)
10 | Alarm(1); /* Next SIGALRM will be delivered in 1 second */
11 | else {
12 | printf("BOOM!\n");
13 | exit(0);
14 | }
15 | }
16 |
17 | int main()
18 | {
19 | Signal(SIGALRM, handler); /* install SIGALRM handler */
20 | Alarm(1); /* Next SIGALRM will be delivered in 1s */
21 |
22 | while (1) {
23 | ; /* Signal handler returns control here each time */
24 | }
25 | exit(0);
26 | }
27 | /* $end alarm */
28 |
--------------------------------------------------------------------------------
/code/ecf/counterprob.c:
--------------------------------------------------------------------------------
1 | /* $begin counterprob */
2 | #include "csapp.h"
3 |
4 | int counter = 0;
5 |
6 | void handler(int sig)
7 | {
8 | counter++;
9 | sleep(1); /* Do some work in the handler */
10 | return;
11 | }
12 |
13 | int main()
14 | {
15 | int i;
16 |
17 | Signal(SIGUSR2, handler);
18 |
19 | if (Fork() == 0) { /* Child */
20 | for (i = 0; i < 5; i++) {
21 | Kill(getppid(), SIGUSR2);
22 | printf("sent SIGUSR2 to parent\n");
23 | }
24 | exit(0);
25 | }
26 |
27 | Wait(NULL);
28 | printf("counter=%d\n", counter);
29 | exit(0);
30 | }
31 | /* $end counterprob */
32 |
--------------------------------------------------------------------------------
/code/ecf/fork.c:
--------------------------------------------------------------------------------
1 | /* $begin fork */
2 | #include "csapp.h"
3 |
4 | int main()
5 | {
6 | pid_t pid;
7 | int x = 1;
8 |
9 | pid = Fork(); //line:ecf:forkreturn
10 | if (pid == 0) { /* Child */
11 | printf("child : x=%d\n", ++x); //line:ecf:childprint
12 | exit(0);
13 | }
14 |
15 | /* Parent */
16 | printf("parent: x=%d\n", --x); //line:ecf:parentprint
17 | exit(0);
18 | }
19 | /* $end fork */
20 |
21 |
--------------------------------------------------------------------------------
/code/ecf/forkprob0.c:
--------------------------------------------------------------------------------
1 | /* $begin forkprob0 */
2 | #include "csapp.h"
3 |
4 | int main()
5 | {
6 | int x = 1;
7 |
8 | if (Fork() == 0)
9 | printf("printf1: x=%d\n", ++x);
10 | printf("printf2: x=%d\n", --x);
11 | exit(0);
12 | }
13 | /* $end forkprob0 */
14 |
15 |
--------------------------------------------------------------------------------
/code/ecf/forkprob1.c:
--------------------------------------------------------------------------------
1 | /* $begin forkprob1 */
2 | #include "csapp.h"
3 |
4 | int main()
5 | {
6 | int i;
7 |
8 | for (i = 0; i < 2; i++)
9 | Fork();
10 | printf("hello\n");
11 | exit(0);
12 | }
13 | /* $end forkprob1 */
14 |
--------------------------------------------------------------------------------
/code/ecf/forkprob2.c:
--------------------------------------------------------------------------------
1 | /* $begin forkprob2 */
2 | #include "csapp.h"
3 |
4 | void end(void)
5 | {
6 | printf("2");
7 | }
8 |
9 | int main()
10 | {
11 | if (Fork() == 0)
12 | atexit(end);
13 | if (Fork() == 0)
14 | printf("0");
15 | else
16 | printf("1");
17 | exit(0);
18 | }
19 | /* $end forkprob2 */
20 |
21 |
--------------------------------------------------------------------------------
/code/ecf/forkprob3.c:
--------------------------------------------------------------------------------
1 | /* $begin forkprob3 */
2 | #include "csapp.h"
3 |
4 | int main()
5 | {
6 | int x = 3;
7 |
8 | if (Fork() != 0)
9 | printf("x=%d\n", ++x);
10 |
11 | printf("x=%d\n", --x);
12 | exit(0);
13 | }
14 | /* $end forkprob3 */
15 |
16 |
--------------------------------------------------------------------------------
/code/ecf/forkprob4.c:
--------------------------------------------------------------------------------
1 | /* $begin forkprob4 */
2 | #include "csapp.h"
3 |
4 | void doit()
5 | {
6 | Fork();
7 | Fork();
8 | printf("hello\n");
9 | return;
10 | }
11 |
12 | int main()
13 | {
14 | doit();
15 | printf("hello\n");
16 | exit(0);
17 | }
18 | /* $end forkprob4 */
19 |
20 |
21 |
--------------------------------------------------------------------------------
/code/ecf/forkprob5.c:
--------------------------------------------------------------------------------
1 | /* $begin forkprob5 */
2 | #include "csapp.h"
3 |
4 | void doit()
5 | {
6 | if (Fork() == 0) {
7 | Fork();
8 | printf("hello\n");
9 | exit(0);
10 | }
11 | return;
12 | }
13 |
14 | int main()
15 | {
16 | doit();
17 | printf("hello\n");
18 | exit(0);
19 | }
20 | /* $end forkprob5 */
21 |
--------------------------------------------------------------------------------
/code/ecf/forkprob6.c:
--------------------------------------------------------------------------------
1 | /* $begin forkprob6 */
2 | #include "csapp.h"
3 |
4 | void doit()
5 | {
6 | if (Fork() == 0) {
7 | Fork();
8 | printf("hello\n");
9 | return;
10 | }
11 | return;
12 | }
13 |
14 | int main()
15 | {
16 | doit();
17 | printf("hello\n");
18 | exit(0);
19 | }
20 | /* $end forkprob6 */
21 |
--------------------------------------------------------------------------------
/code/ecf/forkprob7.c:
--------------------------------------------------------------------------------
1 | /* $begin forkprob7 */
2 | #include "csapp.h"
3 | int counter = 1;
4 |
5 | int main()
6 | {
7 | if (fork() == 0) {
8 | counter--;
9 | exit(0);
10 | }
11 | else {
12 | Wait(NULL);
13 | printf("counter = %d\n", ++counter);
14 | }
15 | exit(0);
16 | }
17 | /* $end forkprob7 */
18 |
--------------------------------------------------------------------------------
/code/ecf/forkprob8.c:
--------------------------------------------------------------------------------
1 | #include "csapp.h"
2 |
3 | /* $begin forkprob8 */
4 | void foo(int n)
5 | {
6 | int i;
7 |
8 | for (i = 0; i < n; i++)
9 | Fork();
10 | printf("hello\n");
11 | exit(0);
12 | }
13 | /* $end forkprob8 */
14 |
15 | int main(int argc, char **argv)
16 | {
17 | if (argc < 2) {
18 | printf("usage: %s \n", argv[0]);
19 | exit(0);
20 | }
21 | foo(atoi(argv[1]));
22 | exit(0);
23 | }
24 |
--------------------------------------------------------------------------------
/code/ecf/hello-asm.sa:
--------------------------------------------------------------------------------
1 | /* $begin hello-s 1 */
2 | .section .data
3 | string:
4 | .ascii "hello, world\n"
5 | string_end:
6 | .equ len, string_end - string
7 |
8 | .section .text
9 | .globl main
10 | main:
11 | # First, call write(1, "hello, world\n", 13)
12 | movl $4, %eax # System call number 4
13 | movl $1, %ebx # stdout has descriptor 1
14 | movl $string, %ecx # Hello world string
15 | movl $len, %edx # String length
16 | int $0x80 # System call code
17 |
18 | # Next, call exit(0)
19 | movl $1, %eax # System call number 0
20 | movl $0, %ebx # Argument is 0
21 | int $0x80 # System call code
22 | /* $end hello-s 1 */
23 |
--------------------------------------------------------------------------------
/code/ecf/kill.c:
--------------------------------------------------------------------------------
1 | /* $begin kill */
2 | #include "csapp.h"
3 |
4 | int main()
5 | {
6 | pid_t pid;
7 |
8 | /* Child sleeps until SIGKILL signal received, then dies */
9 | if ((pid = Fork()) == 0) {
10 | Pause(); /* Wait for a signal to arrive */
11 | printf("control should never reach here!\n");
12 | exit(0);
13 | }
14 |
15 | /* Parent sends a SIGKILL signal to a child */
16 | Kill(pid, SIGKILL);
17 | exit(0);
18 | }
19 | /* $end kill */
20 |
--------------------------------------------------------------------------------
/code/ecf/procmask1.c:
--------------------------------------------------------------------------------
1 | #include "csapp.h"
2 |
3 | void initjobs()
4 | {
5 | }
6 |
7 | void addjob(int pid)
8 | {
9 | }
10 |
11 | void deletejob(int pid)
12 | {
13 | }
14 |
15 | /* $begin procmask1 */
16 | void handler(int sig)
17 | {
18 | pid_t pid;
19 | while ((pid = waitpid(-1, NULL, 0)) > 0) /* Reap a zombie child */
20 | deletejob(pid); /* Delete the child from the job list */
21 | if (errno != ECHILD)
22 | unix_error("waitpid error");
23 | }
24 |
25 | int main(int argc, char **argv)
26 | {
27 | int pid;
28 |
29 | Signal(SIGCHLD, handler);
30 | initjobs(); /* Initialize the job list */
31 |
32 | while (1) {
33 | /* Child process */
34 | if ((pid = Fork()) == 0) {
35 | Execve("/bin/date", argv, NULL);
36 | }
37 |
38 | /* Parent process */
39 | addjob(pid); /* Add the child to the job list */
40 | }
41 | exit(0);
42 | }
43 | /* $end procmask1 */
44 |
--------------------------------------------------------------------------------
/code/ecf/restart.c:
--------------------------------------------------------------------------------
1 | /* $begin restart */
2 | #include "csapp.h"
3 |
4 | sigjmp_buf buf;
5 |
6 | void handler(int sig)
7 | {
8 | siglongjmp(buf, 1);
9 | }
10 |
11 | int main()
12 | {
13 | Signal(SIGINT, handler);
14 |
15 | if (!sigsetjmp(buf, 1))
16 | printf("starting\n");
17 | else
18 | printf("restarting\n");
19 |
20 | while(1) {
21 | Sleep(1);
22 | printf("processing...\n");
23 | }
24 | exit(0);
25 | }
26 | /* $end restart */
27 |
--------------------------------------------------------------------------------
/code/ecf/setjmp.c:
--------------------------------------------------------------------------------
1 | /* $begin setjmp */
2 | #include "csapp.h"
3 |
4 | jmp_buf buf;
5 |
6 | int error1 = 0;
7 | int error2 = 1;
8 |
9 | void foo(void), bar(void);
10 |
11 | int main()
12 | {
13 | int rc;
14 |
15 | rc = setjmp(buf);
16 | if (rc == 0)
17 | foo();
18 | else if (rc == 1)
19 | printf("Detected an error1 condition in foo\n");
20 | else if (rc == 2)
21 | printf("Detected an error2 condition in foo\n");
22 | else
23 | printf("Unknown error condition in foo\n");
24 | exit(0);
25 | }
26 |
27 | /* Deeply nested function foo */
28 | void foo(void)
29 | {
30 | if (error1)
31 | longjmp(buf, 1);
32 | bar();
33 | }
34 |
35 | void bar(void)
36 | {
37 | if (error2)
38 | longjmp(buf, 2);
39 | }
40 | /* $end setjmp */
41 |
--------------------------------------------------------------------------------
/code/ecf/sigint1.c:
--------------------------------------------------------------------------------
1 | /* $begin sigint1 */
2 | #include "csapp.h"
3 |
4 | void handler(int sig) /* SIGINT handler */ //line:ecf:sigint1:beginhandler
5 | {
6 | printf("Caught SIGINT\n"); //line:ecf:sigint1:printhandler
7 | exit(0); //line:ecf:sigint1:exithandler
8 | } //line:ecf:sigint1:endhandler
9 |
10 | int main()
11 | {
12 | /* Install the SIGINT handler */
13 | if (signal(SIGINT, handler) == SIG_ERR) //line:ecf:sigint1:begininstall
14 | unix_error("signal error"); //line:ecf:sigint1:endinstall
15 |
16 | pause(); /* Wait for the receipt of a signal */ //line:ecf:sigint1:pause
17 |
18 | exit(0);
19 | }
20 | /* $end sigint1 */
21 |
--------------------------------------------------------------------------------
/code/ecf/signal1.c:
--------------------------------------------------------------------------------
1 | /* $begin signal1 */
2 | #include "csapp.h"
3 |
4 | void handler1(int sig)
5 | {
6 | pid_t pid;
7 |
8 | if ((pid = waitpid(-1, NULL, 0)) < 0)
9 | unix_error("waitpid error");
10 | printf("Handler reaped child %d\n", (int)pid);
11 | Sleep(2);
12 | return;
13 | }
14 |
15 | int main()
16 | {
17 | int i, n;
18 | char buf[MAXBUF];
19 |
20 | if (signal(SIGCHLD, handler1) == SIG_ERR)
21 | unix_error("signal error");
22 |
23 | /* Parent creates children */
24 | for (i = 0; i < 3; i++) {
25 | if (Fork() == 0) {
26 | printf("Hello from child %d\n", (int)getpid());
27 | Sleep(1);
28 | exit(0);
29 | }
30 | }
31 |
32 | /* Parent waits for terminal input and then processes it */
33 | if ((n = read(STDIN_FILENO, buf, sizeof(buf))) < 0)
34 | unix_error("read");
35 |
36 | printf("Parent processing input\n");
37 | while (1)
38 | ;
39 |
40 | exit(0);
41 | }
42 | /* $end signal1 */
43 |
--------------------------------------------------------------------------------
/code/ecf/signal2.c:
--------------------------------------------------------------------------------
1 | /* $begin signal2 */
2 | #include "csapp.h"
3 |
4 | void handler2(int sig)
5 | {
6 | pid_t pid;
7 |
8 | while ((pid = waitpid(-1, NULL, 0)) > 0)
9 | printf("Handler reaped child %d\n", (int)pid);
10 | if (errno != ECHILD)
11 | unix_error("waitpid error");
12 | Sleep(2);
13 | return;
14 | }
15 |
16 | int main()
17 | {
18 | int i, n;
19 | char buf[MAXBUF];
20 |
21 | if (signal(SIGCHLD, handler2) == SIG_ERR)
22 | unix_error("signal error");
23 |
24 | /* Parent creates children */
25 | for (i = 0; i < 3; i++) {
26 | if (Fork() == 0) {
27 | printf("Hello from child %d\n", (int)getpid());
28 | Sleep(1);
29 | exit(0);
30 | }
31 | }
32 |
33 | /* Parent waits for terminal input and then processes it */
34 | if ((n = read(STDIN_FILENO, buf, sizeof(buf))) < 0)
35 | unix_error("read error");
36 |
37 | printf("Parent processing input\n");
38 | while (1)
39 | ;
40 |
41 | exit(0);
42 | }
43 | /* $end signal2 */
44 |
--------------------------------------------------------------------------------
/code/ecf/signal3.c:
--------------------------------------------------------------------------------
1 | /* $begin signal3 */
2 | #include "csapp.h"
3 |
4 | void handler2(int sig)
5 | {
6 | pid_t pid;
7 |
8 | while ((pid = waitpid(-1, NULL, 0)) > 0)
9 | printf("Handler reaped child %d\n", (int)pid);
10 | if (errno != ECHILD)
11 | unix_error("waitpid error");
12 | Sleep(2);
13 | return;
14 | }
15 |
16 | int main() {
17 | int i, n;
18 | char buf[MAXBUF];
19 | pid_t pid;
20 |
21 | if (signal(SIGCHLD, handler2) == SIG_ERR)
22 | unix_error("signal error");
23 |
24 | /* Parent creates children */
25 | for (i = 0; i < 3; i++) {
26 | pid = Fork();
27 | if (pid == 0) {
28 | printf("Hello from child %d\n", (int)getpid());
29 | Sleep(1);
30 | exit(0);
31 | }
32 | }
33 |
34 | /* Manually restart the read call if it is interrupted */
35 | while ((n = read(STDIN_FILENO, buf, sizeof(buf))) < 0)
36 | if (errno != EINTR)
37 | unix_error("read error");
38 |
39 | printf("Parent processing input\n");
40 | while (1)
41 | ;
42 |
43 | exit(0);
44 | }
45 | /* $end signal3 */
46 |
--------------------------------------------------------------------------------
/code/ecf/signal4.c:
--------------------------------------------------------------------------------
1 | /* $begin signal4 */
2 | #include "csapp.h"
3 |
4 | void handler2(int sig)
5 | {
6 | pid_t pid;
7 |
8 | while ((pid = waitpid(-1, NULL, 0)) > 0)
9 | printf("Handler reaped child %d\n", (int)pid);
10 | if (errno != ECHILD)
11 | unix_error("waitpid error");
12 | Sleep(2);
13 | return;
14 | }
15 |
16 | int main()
17 | {
18 | int i, n;
19 | char buf[MAXBUF];
20 | pid_t pid;
21 |
22 | Signal(SIGCHLD, handler2); /* sigaction error-handling wrapper */
23 |
24 | /* Parent creates children */
25 | for (i = 0; i < 3; i++) {
26 | pid = Fork();
27 | if (pid == 0) {
28 | printf("Hello from child %d\n", (int)getpid());
29 | Sleep(1);
30 | exit(0);
31 | }
32 | }
33 |
34 | /* Parent waits for terminal input and then processes it */
35 | if ((n = read(STDIN_FILENO, buf, sizeof(buf))) < 0)
36 | unix_error("read error");
37 |
38 | printf("Parent processing input\n");
39 | while (1)
40 | ;
41 | exit(0);
42 | }
43 | /* $end signal4 */
44 |
--------------------------------------------------------------------------------
/code/ecf/signalprob0.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | /* $begin signalprob0 */
8 | pid_t pid;
9 | int counter = 2;
10 |
11 | void handler1(int sig) {
12 | counter = counter - 1;
13 | printf("%d", counter);
14 | fflush(stdout);
15 | exit(0);
16 | }
17 |
18 | int main() {
19 | signal(SIGUSR1, handler1);
20 |
21 | printf("%d", counter);
22 | fflush(stdout);
23 |
24 | if ((pid = fork()) == 0) {
25 | while(1) {};
26 | }
27 | kill(pid, SIGUSR1);
28 | waitpid(-1, NULL, 0);
29 | counter = counter + 1;
30 | printf("%d", counter);
31 | exit(0);
32 | }
33 | /* $end signalprob0 */
34 |
--------------------------------------------------------------------------------
/code/ecf/waitpid1.c:
--------------------------------------------------------------------------------
1 | /* $begin waitpid1 */
2 | #include "csapp.h"
3 | #define N 2
4 |
5 | int main()
6 | {
7 | int status, i;
8 | pid_t pid;
9 |
10 | /* Parent creates N children */
11 | for (i = 0; i < N; i++) //line:ecf:waitpid1:for
12 | if ((pid = Fork()) == 0) /* child */ //line:ecf:waitpid1:fork
13 | exit(100+i); //line:ecf:waitpid1:exit
14 |
15 | /* Parent reaps N children in no particular order */
16 | while ((pid = waitpid(-1, &status, 0)) > 0) { //line:ecf:waitpid1:waitpid
17 | if (WIFEXITED(status)) //line:ecf:waitpid1:wifexited
18 | printf("child %d terminated normally with exit status=%d\n",
19 | pid, WEXITSTATUS(status)); //line:ecf:waitpid1:wexitstatus
20 | else
21 | printf("child %d terminated abnormally\n", pid);
22 | }
23 |
24 | /* The only normal termination is if there are no more children */
25 | if (errno != ECHILD) //line:ecf:waitpid1:errno
26 | unix_error("waitpid error");
27 |
28 | exit(0);
29 | }
30 | /* $end waitpid1 */
31 |
--------------------------------------------------------------------------------
/code/ecf/waitpid2.c:
--------------------------------------------------------------------------------
1 | /* $begin waitpid2 */
2 | #include "csapp.h"
3 | #define N 2
4 |
5 | int main()
6 | {
7 | int status, i;
8 | pid_t pid[N], retpid;
9 |
10 | /* Parent creates N children */
11 | for (i = 0; i < N; i++)
12 | if ((pid[i] = Fork()) == 0) /* Child */ //line:ecf:waitpid2:fork
13 | exit(100+i);
14 |
15 | /* Parent reaps N children in order */
16 | i = 0;
17 | while ((retpid = waitpid(pid[i++], &status, 0)) > 0) { //line:ecf:waitpid2:waitpid
18 | if (WIFEXITED(status))
19 | printf("child %d terminated normally with exit status=%d\n",
20 | retpid, WEXITSTATUS(status));
21 | else
22 | printf("child %d terminated abnormally\n", retpid);
23 | }
24 |
25 | /* The only normal termination is if there are no more children */
26 | if (errno != ECHILD)
27 | unix_error("waitpid error");
28 |
29 | exit(0);
30 | }
31 | /* $end waitpid2 */
32 |
--------------------------------------------------------------------------------
/code/ecf/waitprob0.c:
--------------------------------------------------------------------------------
1 | #include "csapp.h"
2 |
3 | /* $begin waitprob0 */
4 | int main()
5 | {
6 | if (Fork() == 0) {
7 | printf("a");
8 | }
9 | else {
10 | printf("b");
11 | waitpid(-1, NULL, 0);
12 | }
13 | printf("c");
14 | exit(0);
15 | }
16 | /* $end waitprob0 */
17 |
--------------------------------------------------------------------------------
/code/ecf/waitprob1.c:
--------------------------------------------------------------------------------
1 | #include "csapp.h"
2 |
3 | /* $begin waitprob1 */
4 | int main()
5 | {
6 | int status;
7 | pid_t pid;
8 |
9 | printf("Hello\n");
10 | pid = Fork();
11 | printf("%d\n", !pid);
12 | if (pid != 0) {
13 | if (waitpid(-1, &status, 0) > 0) {
14 | if (WIFEXITED(status) != 0)
15 | printf("%d\n", WEXITSTATUS(status));
16 | }
17 | }
18 | printf("Bye\n");
19 | exit(2);
20 | }
21 | /* $end waitprob1 */
22 |
--------------------------------------------------------------------------------
/code/ecf/waitprob3.c:
--------------------------------------------------------------------------------
1 | #include "csapp.h"
2 |
3 | /* $begin waitprob3 */
4 | int main()
5 | {
6 | if (fork() == 0) {
7 | printf("a");
8 | exit(0);
9 | }
10 | else {
11 | printf("b");
12 | waitpid(-1, NULL, 0);
13 | }
14 | printf("c");
15 | exit(0);
16 | }
17 | /* $end waitprob3 */
18 |
--------------------------------------------------------------------------------
/code/intro/hello.c:
--------------------------------------------------------------------------------
1 | /* $begin hello */
2 | #include
3 |
4 | int main()
5 | {
6 | printf("hello, world\n");
7 | }
8 | /* $end hello */
9 |
10 |
--------------------------------------------------------------------------------
/code/link/addvec.c:
--------------------------------------------------------------------------------
1 | /* addvec.c */
2 | /* $begin addvec */
3 | void addvec(int *x, int *y,
4 | int *z, int n)
5 | {
6 | int i;
7 |
8 | for (i = 0; i < n; i++)
9 | z[i] = x[i] + y[i];
10 | }
11 | /* $end addvec */
12 |
13 |
--------------------------------------------------------------------------------
/code/link/dll.c:
--------------------------------------------------------------------------------
1 | /* $begin dll */
2 | #include
3 | #include
4 | #include
5 |
6 | int x[2] = {1, 2};
7 | int y[2] = {3, 4};
8 | int z[2];
9 |
10 | int main()
11 | {
12 | void *handle;
13 | void (*addvec)(int *, int *, int *, int);
14 | char *error;
15 |
16 | /* dynamically load the shared library that contains addvec() */
17 | handle = dlopen("./libvector.so", RTLD_LAZY);
18 | if (!handle) {
19 | fprintf(stderr, "%s\n", dlerror());
20 | exit(1);
21 | }
22 |
23 | /* get a pointer to the addvec() function we just loaded */
24 | addvec = dlsym(handle, "addvec");
25 | if ((error = dlerror()) != NULL) {
26 | fprintf(stderr, "%s\n", error);
27 | exit(1);
28 | }
29 |
30 | /* Now we can call addvec() it just like any other function */
31 | addvec(x, y, z, 2);
32 | printf("z = [%d %d]\n", z[0], z[1]);
33 |
34 | /* unload the shared library */
35 | if (dlclose(handle) < 0) {
36 | fprintf(stderr, "%s\n", dlerror());
37 | exit(1);
38 | }
39 | return 0;
40 | }
41 | /* $end dll */
42 |
43 |
--------------------------------------------------------------------------------
/code/link/elfstructs.c:
--------------------------------------------------------------------------------
1 | /* $begin elfsymbol */
2 | typedef struct {
3 | int name; /* string table offset */
4 | int value; /* section offset, or VM address */
5 | int size; /* object size in bytes */
6 | char type:4, /* data, func, section, or src file name (4 bits) */
7 | binding:4; /* local or global (4 bits) */
8 | char reserved; /* unused */
9 | char section; /* section header index, ABS, UNDEF, */
10 | /* or COMMON */
11 | } Elf_Symbol;
12 | /* $end elfsymbol */
13 |
14 | /* $begin elfrelo */
15 | typedef struct {
16 | int offset; /* offset of the reference to relocate */
17 | int symbol:24, /* symbol the reference should point to */
18 | type:8; /* relocation type */
19 | } Elf32_Rel;
20 | /* $end elfrelo */
21 |
22 |
--------------------------------------------------------------------------------
/code/link/main.c:
--------------------------------------------------------------------------------
1 | /* $begin main */
2 | /* main.c */
3 | void swap();
4 |
5 | int buf[2] = {1, 2};
6 |
7 | int main()
8 | {
9 | swap();
10 | return 0;
11 | }
12 | /* $end main */
13 |
14 |
--------------------------------------------------------------------------------
/code/link/main2.c:
--------------------------------------------------------------------------------
1 | /* $begin main2 */
2 | /* main2.c */
3 | #include
4 | #include "vector.h"
5 |
6 | int x[2] = {1, 2};
7 | int y[2] = {3, 4};
8 | int z[2];
9 |
10 | int main()
11 | {
12 | addvec(x, y, z, 2);
13 | printf("z = [%d %d]\n", z[0], z[1]);
14 | return 0;
15 | }
16 | /* $end main2 */
17 |
18 |
--------------------------------------------------------------------------------
/code/link/multvec.c:
--------------------------------------------------------------------------------
1 | /* multvec.c */
2 | /* $begin multvec */
3 | void multvec(int *x, int *y,
4 | int *z, int n)
5 | {
6 | int i;
7 |
8 | for (i = 0; i < n; i++)
9 | z[i] = x[i] * y[i];
10 | }
11 | /* $end multvec */
12 |
13 |
--------------------------------------------------------------------------------
/code/link/swap.c:
--------------------------------------------------------------------------------
1 | /* $begin swap */
2 | /* swap.c */
3 | extern int buf[];
4 |
5 | int *bufp0 = &buf[0];
6 | int *bufp1;
7 |
8 | void swap()
9 | {
10 | int temp;
11 |
12 | bufp1 = &buf[1];
13 | temp = *bufp0;
14 | *bufp0 = *bufp1;
15 | *bufp1 = temp;
16 | }
17 | /* $end swap */
18 |
19 |
--------------------------------------------------------------------------------
/code/netp/echo.c:
--------------------------------------------------------------------------------
1 | /*
2 | * echo - read and echo text lines until client closes connection
3 | */
4 | /* $begin echo */
5 | #include "csapp.h"
6 |
7 | void echo(int connfd)
8 | {
9 | size_t n;
10 | char buf[MAXLINE];
11 | rio_t rio;
12 |
13 | Rio_readinitb(&rio, connfd);
14 | while((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0) { //line:netp:echo:eof
15 | printf("server received %d bytes\n", n);
16 | Rio_writen(connfd, buf, n);
17 | }
18 | }
19 | /* $end echo */
20 |
21 |
--------------------------------------------------------------------------------
/code/netp/echoclient.c:
--------------------------------------------------------------------------------
1 | /*
2 | * echoclient.c - An echo client
3 | */
4 | /* $begin echoclientmain */
5 | #include "csapp.h"
6 |
7 | int main(int argc, char **argv)
8 | {
9 | int clientfd, port;
10 | char *host, buf[MAXLINE];
11 | rio_t rio;
12 |
13 | if (argc != 3) {
14 | fprintf(stderr, "usage: %s \n", argv[0]);
15 | exit(0);
16 | }
17 | host = argv[1];
18 | port = atoi(argv[2]);
19 |
20 | clientfd = Open_clientfd(host, port);
21 | Rio_readinitb(&rio, clientfd);
22 |
23 | while (Fgets(buf, MAXLINE, stdin) != NULL) {
24 | Rio_writen(clientfd, buf, strlen(buf));
25 | Rio_readlineb(&rio, buf, MAXLINE);
26 | Fputs(buf, stdout);
27 | }
28 | Close(clientfd); //line:netp:echoclient:close
29 | exit(0);
30 | }
31 | /* $end echoclientmain */
32 |
--------------------------------------------------------------------------------
/code/netp/echoserveri.c:
--------------------------------------------------------------------------------
1 | /*
2 | * echoserveri.c - An iterative echo server
3 | */
4 | /* $begin echoserverimain */
5 | #include "csapp.h"
6 |
7 | void echo(int connfd);
8 |
9 | int main(int argc, char **argv)
10 | {
11 | int listenfd, connfd, port, clientlen;
12 | struct sockaddr_in clientaddr;
13 | struct hostent *hp;
14 | char *haddrp;
15 | if (argc != 2) {
16 | fprintf(stderr, "usage: %s \n", argv[0]);
17 | exit(0);
18 | }
19 | port = atoi(argv[1]);
20 |
21 | listenfd = Open_listenfd(port);
22 | while (1) {
23 | clientlen = sizeof(clientaddr);
24 | connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen);
25 |
26 | /* determine the domain name and IP address of the client */
27 | hp = Gethostbyaddr((const char *)&clientaddr.sin_addr.s_addr,
28 | sizeof(clientaddr.sin_addr.s_addr), AF_INET);
29 | haddrp = inet_ntoa(clientaddr.sin_addr);
30 | printf("server connected to %s (%s)\n", hp->h_name, haddrp);
31 |
32 | echo(connfd);
33 | Close(connfd);
34 | }
35 | exit(0);
36 | }
37 | /* $end echoserverimain */
38 |
--------------------------------------------------------------------------------
/code/netp/hostinfo.c:
--------------------------------------------------------------------------------
1 | /* $begin hostinfo */
2 | #include "csapp.h"
3 |
4 | int main(int argc, char **argv)
5 | {
6 | char **pp;
7 | struct in_addr addr;
8 | struct hostent *hostp;
9 |
10 | if (argc != 2) {
11 | fprintf(stderr, "usage: %s \n",
12 | argv[0]);
13 | exit(0);
14 | }
15 |
16 | if (inet_aton(argv[1], &addr) != 0)
17 | hostp = Gethostbyaddr((const char *)&addr, sizeof(addr), AF_INET);
18 | else
19 | hostp = Gethostbyname(argv[1]);
20 |
21 | printf("official hostname: %s\n", hostp->h_name);
22 |
23 | for (pp = hostp->h_aliases; *pp != NULL; pp++)
24 | printf("alias: %s\n", *pp);
25 |
26 | for (pp = hostp->h_addr_list; *pp != NULL; pp++) {
27 | addr.s_addr = ((struct in_addr *)*pp)->s_addr;
28 | printf("address: %s\n", inet_ntoa(addr));
29 | }
30 | exit(0);
31 | }
32 | /* $end hostinfo */
33 |
--------------------------------------------------------------------------------
/code/netp/tiny/cgi-bin/adder.c:
--------------------------------------------------------------------------------
1 | /*
2 | * adder.c - a minimal CGI program that adds two numbers together
3 | */
4 | /* $begin adder */
5 | #include "csapp.h"
6 |
7 | int main(void) {
8 | char *buf, *p;
9 | char arg1[MAXLINE], arg2[MAXLINE], content[MAXLINE];
10 | int n1=0, n2=0;
11 |
12 | /* Extract the two arguments */
13 | if ((buf = getenv("QUERY_STRING")) != NULL) {
14 | p = strchr(buf, '&');
15 | *p = '\0';
16 | strcpy(arg1, buf);
17 | strcpy(arg2, p+1);
18 | n1 = atoi(arg1);
19 | n2 = atoi(arg2);
20 | }
21 |
22 | /* Make the response body */
23 | sprintf(content, "Welcome to add.com: ");
24 | sprintf(content, "%sTHE Internet addition portal.\r\n", content);
25 | sprintf(content, "%sThe answer is: %d + %d = %d\r\n
",
26 | content, n1, n2, n1 + n2);
27 | sprintf(content, "%sThanks for visiting!\r\n", content);
28 |
29 | /* Generate the HTTP response */
30 | printf("Content-length: %d\r\n", (int)strlen(content));
31 | printf("Content-type: text/html\r\n\r\n");
32 | printf("%s", content);
33 | fflush(stdout);
34 | exit(0);
35 | }
36 | /* $end adder */
37 |
--------------------------------------------------------------------------------
/csapp.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/csapp.jpg
--------------------------------------------------------------------------------
/exercise/README:
--------------------------------------------------------------------------------
1 | 这个文件对这个文件夹下面的文件做出说明。
2 |
3 | 00-topic.txt: 这个文件收集了这本书的所有的家庭作业的题目
4 | ex*: 其他的所有文件都是题目的解答
5 | t*: 以 t 为前缀的文件是对题目的测试
6 |
7 | mofaph
8 | 2012/11/24
9 |
--------------------------------------------------------------------------------
/exercise/ex10-10.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 10.10
3 | *
4 | * mofaph@gmail.com
5 | * 2013-5-11
6 | *
7 | * 感谢 @oymy,指出了这道题应该使用 dup2()。
8 | *
9 | * $ cc -I../common ../common/csapp.c ex10-10.c -lpthread
10 | */
11 |
12 | #include "csapp.h"
13 |
14 | int main(int argc, char **argv)
15 | {
16 | int n;
17 | rio_t rio;
18 | char buf[MAXLINE];
19 |
20 | if (argc > 2) {
21 | fprintf(stderr, "usage: %s [filename]\n", argv[0]);
22 | return -1;
23 | }
24 |
25 | /* 这里将标准输入的文件描述符,重定位到输入文件的描述符 */
26 | if (argc == 2) {
27 | char *filename = argv[1];
28 | int fd = Open(filename, O_RDONLY, 0);
29 | int ret = dup2(fd, STDIN_FILENO); /* 将标准输入重定位到 fd */
30 | if (ret < 0) {
31 | perror("dup2");
32 | return -1;
33 | }
34 | }
35 |
36 | /* 没有输入文件名,将标准输入拷贝到标准输出 */
37 | Rio_readinitb(&rio, STDIN_FILENO);
38 | while ((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0)
39 | Rio_writen(STDOUT_FILENO, buf, n);
40 |
41 | return 0;
42 | }
43 |
--------------------------------------------------------------------------------
/exercise/ex10-2.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 10.2
3 | *
4 | * mofaph@gmail.com
5 | *
6 | * 假设磁盘文件 foobar.txt 由 6 个 ASCII 码字符“foobar”组成。那么,下列程序的输
7 | * 出是什么?
8 | *
9 | * $ echo "foobar" > foobar.txt
10 | * $ cc -I../common ../common/csapp.c ex10-2.c -lpthread
11 | */
12 |
13 | #include "csapp.h"
14 |
15 | int main()
16 | {
17 | int fd1, fd2;
18 | char c;
19 |
20 | fd1 = Open("foobar.txt", O_RDONLY, 0);
21 | fd2 = Open("foobar.txt", O_RDONLY, 0);
22 | Read(fd1, &c, 1);
23 | Read(fd2, &c, 1);
24 | printf("c = %c\n", c);
25 | exit(0);
26 | }
27 |
--------------------------------------------------------------------------------
/exercise/ex10-3.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 10.3
3 | *
4 | * 就像前面 10.2 那样,假设磁盘文件 foobar.txt 由 6 个 ASCII 码字符“foobar”组成。
5 | * 那么下列程序的输出是什么?
6 | *
7 | * $ echo "foobar" > foobar.txt
8 | * $ cc -I../common ../common/csapp.c ex10-3.c -lpthread
9 | */
10 |
11 | #include "csapp.h"
12 |
13 | int main()
14 | {
15 | int fd;
16 | char c;
17 |
18 | fd = Open("foobar.txt", O_RDONLY, 0);
19 | if (Fork() == 0) { /* child */
20 | Read(fd, &c, 1);
21 | exit(0);
22 | }
23 |
24 | /* parent */
25 | Wait(NULL);
26 | Read(fd, &c, 1);
27 | printf("c = %c\n", c);
28 | exit(0);
29 | }
30 |
--------------------------------------------------------------------------------
/exercise/ex10-5.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 10.5
3 | *
4 | * mofaph@gmail.com
5 | *
6 | * 假设磁盘文件 foobar.txt 由 6 个 ASCII 码字符“foobar”组成,那么下列程序的输出
7 | * 是什么?
8 | *
9 | * $ echo "foobar" > foobar.txt
10 | * $ cc -I../common ../common/csapp.c ex10-5.c -lpthread
11 | */
12 |
13 | #include "csapp.h"
14 |
15 | int main()
16 | {
17 | int fd1, fd2;
18 | char c;
19 |
20 | fd1 = Open("foobar.txt", O_RDONLY, 0);
21 | fd2 = Open("foobar.txt", O_RDONLY, 0);
22 | Read(fd2, &c, 1);
23 | Dup2(fd2, fd1);
24 | Read(fd1, &c, 1);
25 | printf("c = %c\n", c);
26 | exit(0);
27 | }
28 |
--------------------------------------------------------------------------------
/exercise/ex10-6.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 10.6
3 | *
4 | * mofaph@gmail.com
5 | * 2013/5/11
6 | *
7 | * 下面程序的输出是什么?
8 | *
9 | * $ touch {foo,bar,baz}.txt
10 | * $ cc -I../common ../common/csapp.c ex10-6.c -lpthread
11 | */
12 |
13 | #include "csapp.h"
14 |
15 | int main(void)
16 | {
17 | int fd1, fd2;
18 |
19 | fd1 = Open("foo.txt", O_RDONLY, 0); /* fd1: 3 */
20 | fd2 = Open("bar.txt", O_RDONLY, 0); /* fd2: 4 */
21 | Close(fd2);
22 | fd2 = Open("baz.txt", O_RDONLY, 0); /* fd2: 4 */
23 | printf("fd2 = %d\n", fd2);
24 | exit(0);
25 | }
26 |
--------------------------------------------------------------------------------
/exercise/ex10-7.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 10.7
3 | *
4 | * mofaph@gmail.com
5 | * 2013-5-11
6 | *
7 | * $ cc -I../common ../common/csapp.c ex10-7.c -lpthread
8 | * # 注意,上面链接到 pthread 库不是代码必须的,是由于 csapp.c 中需要
9 | */
10 |
11 | #include "csapp.h"
12 |
13 | #undef MAXBUF
14 | #define MAXBUF 6
15 |
16 | #undef MAXLINE
17 | #define MAXLINE 10
18 |
19 | int main(int argc, char **argv)
20 | {
21 | int n;
22 | rio_t rio;
23 | char buf[MAXLINE];
24 | int count = 0; /* 记录 buf 中已经读入的字符数 */
25 |
26 | Rio_readinitb(&rio, STDIN_FILENO);
27 | n = Rio_readnb(&rio, buf, MAXLINE);
28 | while (n > 0) {
29 | count += n;
30 | if (count >= MAXBUF) {
31 | Rio_writen(STDOUT_FILENO, buf, MAXBUF);
32 | count -= MAXBUF;
33 | if (count > 0)
34 | memmove(buf, buf+MAXBUF, count);
35 | }
36 | n = Rio_readnb(&rio, buf+count, MAXLINE-count);
37 | }
38 |
39 | return 0;
40 | }
41 |
--------------------------------------------------------------------------------
/exercise/ex10-9.txt:
--------------------------------------------------------------------------------
1 | 10.9
2 |
3 | bskim45@gmail.com
4 | 2013-12-17
5 | --------------------------------------------------------------------------------
6 |
7 | Before the call to execve, the child process opens foo.txt as descriptor 3,
8 | redirects stdin to foo.txt, and then (here is the kicker) closes descriptor 3:
9 |
10 | if (Fork() == 0) { /* Child */
11 | /* The Shell may be run these code? */
12 | fd = Open("foo.txt", O_RDONLY, 0); /* fd == 3 */
13 | Dup2(fd, STDIN_FILENO);
14 | Close(fd);
15 | Execve("fstatcheck", argv, envp);
16 | }
17 |
18 | When fstatcheck begins running in the child, there are exactly three open files,
19 | corresponding to descriptors 0, 1, and 2, with descriptor 1 redirected to
20 | foo.txt.
21 |
--------------------------------------------------------------------------------
/exercise/ex11-10/godzilla.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/exercise/ex11-10/godzilla.gif
--------------------------------------------------------------------------------
/exercise/ex11-10/godzilla.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/exercise/ex11-10/godzilla.jpg
--------------------------------------------------------------------------------
/exercise/ex11-10/home.html:
--------------------------------------------------------------------------------
1 | Welcome to add.com
2 |
--------------------------------------------------------------------------------
/exercise/ex11-11/Sequence.mpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/exercise/ex11-11/Sequence.mpg
--------------------------------------------------------------------------------
/exercise/ex11-11/godzilla.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/exercise/ex11-11/godzilla.gif
--------------------------------------------------------------------------------
/exercise/ex11-11/godzilla.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/exercise/ex11-11/godzilla.jpg
--------------------------------------------------------------------------------
/exercise/ex11-11/home.html:
--------------------------------------------------------------------------------
1 | Welcome to add.com
2 |
--------------------------------------------------------------------------------
/exercise/ex11-12/Sequence.mpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/exercise/ex11-12/Sequence.mpg
--------------------------------------------------------------------------------
/exercise/ex11-12/godzilla.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/exercise/ex11-12/godzilla.gif
--------------------------------------------------------------------------------
/exercise/ex11-12/godzilla.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/exercise/ex11-12/godzilla.jpg
--------------------------------------------------------------------------------
/exercise/ex11-12/home.html:
--------------------------------------------------------------------------------
1 | Welcome to add.com
2 |
--------------------------------------------------------------------------------
/exercise/ex11-13/Sequence.mpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/exercise/ex11-13/Sequence.mpg
--------------------------------------------------------------------------------
/exercise/ex11-13/godzilla.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/exercise/ex11-13/godzilla.gif
--------------------------------------------------------------------------------
/exercise/ex11-13/godzilla.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/exercise/ex11-13/godzilla.jpg
--------------------------------------------------------------------------------
/exercise/ex11-13/home.html:
--------------------------------------------------------------------------------
1 | Welcome to add.com
2 |
--------------------------------------------------------------------------------
/exercise/ex11-2.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 11.2
3 | *
4 | * mofaph@gmail.com
5 | * 2013-5-13
6 | *
7 | * 编写程序 hex2dd.c,它将十六进制参数转换为点分十进制串并打印出结果。例如:
8 | *
9 | * unix> cc ex11-2.c -o hex2dd
10 | * unix> ./hex2dd 0x8002c2f2
11 | * 128.2.194.242
12 | */
13 |
14 | #include
15 | #include
16 |
17 | #include
18 | #include
19 |
20 | #include
21 | #include
22 | #include
23 |
24 | int main(int argc, char *argv[])
25 | {
26 | if (argc != 2) {
27 | fprintf(stderr, "usage: %s \n", argv[0]);
28 | return -1;
29 | }
30 |
31 | /* 1. 将接收的字符串参数转换成整数 */
32 | unsigned int host = strtoul(argv[1], NULL, 0);
33 | if (host == ULONG_MAX && errno == ERANGE) {
34 | perror("strtoul");
35 | return -1;
36 | }
37 |
38 | /* 2. 将数字转换成网络字节序 */
39 | unsigned int net = htonl(host);
40 |
41 | /* 3. 将整数转换成点分十进制 */
42 | struct in_addr in;
43 | in.s_addr = net;
44 | char *decimal = inet_ntoa(in);
45 | printf("%s\n", decimal);
46 |
47 | return 0;
48 | }
49 |
--------------------------------------------------------------------------------
/exercise/ex11-3.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 11.3
3 | *
4 | * mofaph@gmail.com
5 | * 2013-5-13
6 | *
7 | * 编写程序 dd2hex.c,它将它的点分十进制参数转换为十六进制数并打印出结果。例如
8 | *
9 | * unix> cc ex11-3.c -o dd2hex
10 | * unix> ./dd2hex 128.2.194.242
11 | * 0x8002c2f2
12 | */
13 |
14 | #include
15 |
16 | #include
17 | #include
18 | #include
19 |
20 | int main(int argc, char *argv[])
21 | {
22 | /* 0. 检查参数是否正确 */
23 | if (argc != 2) {
24 | fprintf(stderr, "usage: %s \n", argv[0]);
25 | return -1;
26 | }
27 |
28 | /* 1. 将点分十进制转换成网络字节序的 IP 地址 */
29 | struct in_addr net;
30 | int ret = inet_aton(argv[1], &net);
31 | if (ret == 0) {
32 | fprintf(stderr, "inet_aton: convert %s failed\n", argv[1]);
33 | return -1;
34 | }
35 |
36 | /* 2. 将网络字节序的 IP 地址转换成本地字节序 */
37 | unsigned int host = ntohl(net.s_addr);
38 |
39 | /* 3. 打印结果 */
40 | printf("0x%x\n", host);
41 |
42 | return 0;
43 | }
44 |
--------------------------------------------------------------------------------
/exercise/ex11-6/godzilla.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/exercise/ex11-6/godzilla.gif
--------------------------------------------------------------------------------
/exercise/ex11-6/godzilla.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/exercise/ex11-6/godzilla.jpg
--------------------------------------------------------------------------------
/exercise/ex11-6/home.html:
--------------------------------------------------------------------------------
1 | Welcome to add.com
2 |
--------------------------------------------------------------------------------
/exercise/ex11-7/Sequence.mpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/exercise/ex11-7/Sequence.mpg
--------------------------------------------------------------------------------
/exercise/ex11-7/godzilla.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/exercise/ex11-7/godzilla.gif
--------------------------------------------------------------------------------
/exercise/ex11-7/godzilla.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/exercise/ex11-7/godzilla.jpg
--------------------------------------------------------------------------------
/exercise/ex11-7/home.html:
--------------------------------------------------------------------------------
1 | Welcome to add.com
2 |
--------------------------------------------------------------------------------
/exercise/ex11-8/godzilla.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/exercise/ex11-8/godzilla.gif
--------------------------------------------------------------------------------
/exercise/ex11-8/godzilla.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/exercise/ex11-8/godzilla.jpg
--------------------------------------------------------------------------------
/exercise/ex11-8/home.html:
--------------------------------------------------------------------------------
1 | Welcome to add.com
2 |
--------------------------------------------------------------------------------
/exercise/ex11-9/godzilla.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/exercise/ex11-9/godzilla.gif
--------------------------------------------------------------------------------
/exercise/ex11-9/godzilla.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/exercise/ex11-9/godzilla.jpg
--------------------------------------------------------------------------------
/exercise/ex11-9/home.html:
--------------------------------------------------------------------------------
1 | Welcome to add.com
2 |
--------------------------------------------------------------------------------
/exercise/ex2-36.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 练习题 2.36
3 | *
4 | * 对于数据类型 int 为 32 位的情况,设计一个版本的 tmult_ok 函数(见练习题 2.35),
5 | * 要使用 64 位精度的数据类型 long long,而不使用除法。
6 | */
7 |
8 | /*
9 | * Determine whether arguments can be multipled without overflow
10 | *
11 | * overflow: 0, normal: 1
12 | */
13 | int tmult_ok(int x, int y)
14 | {
15 | long long result = (long long)x * (long long)y;
16 | int iresult = x * y;
17 |
18 | return result == iresult;
19 | }
20 |
21 | int book_tmult_ok(int x, int y)
22 | {
23 | /* Compute product without overflow */
24 | long long pll = (long long)x * y;
25 | /* See if casting to int preserves value */
26 | return pll == (int)pll;
27 | }
28 |
--------------------------------------------------------------------------------
/exercise/ex2-42.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 练习题 2.42
3 | *
4 | * 写一个函数 div16,对于整数参数 x 返回 x/16 的值。你的函数不能使用除法、模运算、
5 | * 乘法、任何条件语句(if 或者 ?:)、任何比较运算符(例如 <、>或==)或任何循环。
6 | * 你可以假设数据类型 int 是 32 位长,使用补码表示,而右移是算术右移。
7 | */
8 |
9 | /*
10 | * 这里用到了左移运算符,不知符不符合要求
11 | */
12 | int div16(int x)
13 | {
14 | int sign = (x & (1<<31)) >> 31; /* sign 的位级表示是全 0 或者全 1 */
15 | return (x + (sign & 0x0F)) >> 4;
16 | }
17 |
18 | /*
19 | * 书本的实现更加简洁优雅
20 | *
21 | * 这里唯一的挑战是不用任何测试或条件运算计算偏置值。我们利用了一个诀窍,表达式
22 | * x>>31 产生一个字,如果 x 是负数,这个字为全 1,否则为全 0.通过掩码屏蔽适当的位,
23 | * 我们就得到期望的偏置值。
24 | */
25 | int book_div16(int x)
26 | {
27 | /* Compute bias to be either 0 (x >= 0) or 15 (x < 0) */
28 | int bias = (x >> 31) & 0xF;
29 | return (x + bias) >> 4;
30 | }
31 |
--------------------------------------------------------------------------------
/exercise/ex2-58.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 练习题 2.58
3 | *
4 | * 编写过程 is_little_endian,当在小端法机器上编译和运行时返回 1,在大端法机器上
5 | * 编译运行时返回 0。这个程序应该可以运行在任何机器上,无论机器的字长是多少。
6 | */
7 | int is_little_endian(void)
8 | {
9 | int i = 1;
10 | char *p = (char *)&i;
11 |
12 | /*
13 | * 小端法的机器上,最低有效字节是 1
14 | * 大端法的机器上,最低有效字节是 0
15 | */
16 | return *p;
17 | }
18 |
--------------------------------------------------------------------------------
/exercise/ex2-59.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 练习题 2.59
3 | *
4 | * 编写一个 C 表达式,使它生成一个字,由 x 的最低有效字节和 y 中剩下的字节组成。
5 | * 对于运算数 x=0x89ABCDEF 和 y=0x76543210,就得到 0x765432EF。
6 | */
7 | int combine_word(unsigned x, unsigned y)
8 | {
9 | return (x & 0xFF) | (y & ~0xFF);
10 | }
11 |
--------------------------------------------------------------------------------
/exercise/ex2-60.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 练习题 2.60
3 | *
4 | * 假设我们将一个 w 位的字中的字节从 0(最低位)到 w/8-1(最高位)编号。写出下面
5 | * C 函数的代码,它会返回一个无符号值,其中参数 x 的字节 i 被替换成字节 b:
6 | *
7 | * unsigned replace_byte(unsigned x, unsigned char b, int i);
8 | *
9 | * 以下的一些示例,说明了这个函数该如何工作:
10 | *
11 | * replace_byte(0x12345678, 0xAB, 2) --> 0x12AB5678
12 | * replace_byte(0x12345678, 0xAB, 0) --> 0x123456AB
13 | */
14 |
15 | unsigned replace_byte(unsigned x, unsigned char b, int i)
16 | {
17 | /* 1. 首先将 0x12345678 变为 0x12005678 */
18 | int w = sizeof(int) - 1; /* 取值范围: 0~3 */
19 | int shift_left = (i & w)<<3;
20 | unsigned m = x & ~(0xFF << shift_left);
21 |
22 | /* 2. 将 0xAB 左移 2 两个字节得到数值 0x00AB0000 */
23 | unsigned int n = (unsigned)b << shift_left;
24 |
25 | /* 3. 将 0x12005678+0x00AB0000 作为结果返回 */
26 | return m + n;
27 | }
28 |
--------------------------------------------------------------------------------
/exercise/ex2-62.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 练习题 2.62
3 | *
4 | * 编写一个函数 int_shifts_are_logical(),在对 int 类型的数使用算术右移的机器上运
5 | * 行时,这个函数生成 1,而其他情况下生成 0。你的代码应该可以运行在任何字长的机器
6 | * 上。在几种机器上测试你的代码。
7 | */
8 |
9 | #include
10 |
11 | int int_shifts_are_logical(void)
12 | {
13 | int x = (~0 - 1) >> 1;
14 |
15 | return x != INT_MAX;
16 | }
17 |
--------------------------------------------------------------------------------
/exercise/ex2-63.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 练习题 2.63
3 | *
4 | * 将下面的 C 函数代码补充完整。函数 srl 用算术右移(由值 xsra 给出)来完成逻辑右
5 | * 移,后面的其他操作不包括右移或者除法。函数 sra 用逻辑右移(由值 xsrl 给出)来
6 | * 完成算术右移,后面的其他操作不包括右移或者除法。可以通过计算8*sizeof(int) 来确
7 | * 定数据类型 int 中的位数 w。位移量 k 的取值范围位 0~w-1。
8 | */
9 |
10 | static int w = sizeof(int) << 3;
11 |
12 | int sra(int x, int k)
13 | {
14 | /* Perform shift logically */
15 | int xsrl = (unsigned) x >> k;
16 |
17 | int sign = ((1 << (w - 1 - k)) & xsrl) << 1;
18 | int t = ~((1 << (w - k)) - 1); /* t=[11...1100...00], w-1...w-k 位全 1 */
19 |
20 | /*
21 | * sign = 0, n = 0
22 | * sign = [0...010...0], n = t
23 | */
24 | int n = t + (sign ^ (1 << (w - k)));
25 |
26 | return n + xsrl;
27 | }
28 |
29 | unsigned srl(unsigned x, int k)
30 | {
31 | /* Perform shift arithmetically */
32 | unsigned xsra = (int) x >> k;
33 | return xsra & ((1 << (w-k)) - 1);
34 | }
35 |
--------------------------------------------------------------------------------
/exercise/ex2-64.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 写出代码实现如下函数:
3 | *
4 | * Return 1 when any even bit of x equals 1; 0 otherwise. Assume w=32
5 | *
6 | * int any_even_one(unsigned x);
7 | *
8 | * 函数应该遵循位级整数编码规则,不过你可以假设数据类型 int 有 w=32 位。
9 | */
10 |
11 | int any_even_one(unsigned x)
12 | {
13 | return (x & 0x5555) & 1;
14 | }
15 |
--------------------------------------------------------------------------------
/exercise/ex2-65.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 练习题 2.65
3 | *
4 | * Return 1 when x contains an even number of 1s; 0 otherwise.
5 | * Assume w=32
6 | *
7 | * 解决这个问题的关键是,我们利用了异或运算的一个属性:相同的位异或结果为 0。异或
8 | * 可以看作没有进位的加法。
9 | *
10 | * 我们现在可以假定 int 的宽度为 32 位。如果我们把高 16 位和底 16 位取异或,那么
11 | * 相同的的位会变为 0。也就是说,两个有 1 的相同的位变为 0 了。所有余下来的位都是
12 | * 取异或时两个位级表示不相同的。依次类推,最终我们将会在第 0 位得到一个数。如果
13 | * 这个数是 0 的话,那么就说明这个整数具有偶数个 1(0 也是偶数);如果是 1 的话,
14 | * 说明这个整数具有奇数个 1。
15 | *
16 | * 我们只需要将最终的结果和 1 进行与运算,就可以判断这个整数是有奇数个 1 还是偶数
17 | * 个 1 了。
18 | *
19 | * 在解决这个问题之前,我曾经想过把 x 变为 00...0011...11 这样的形式。还有将 x 左
20 | * 移和右移,然后进行与运算。
21 | *
22 | * 最终想到的这个解决方法,是我在想对两个数进行或运算和与运算之后。或运算将所有有
23 | * 1 的位保存下来,而与运算将所有有相同的 1 的位保存下来。如果将或运算和与运算的
24 | * 结果保存下来,我们就得到了唯一具有 1 的所有位。消去的 1 都是成对消去的,而保留
25 | * 下来的,都是不成对的。而我们如果能够这样进行运算知道只剩下一位的话,那么就可以
26 | * 判断奇偶数了。然后,我们会发现这样的运算性质正好是异或运算所具有的。
27 | */
28 | int even_ones(unsigned x)
29 | {
30 | x ^= x >> 16;
31 | x ^= x >> 8;
32 | x ^= x >> 4;
33 | x ^= x >> 2;
34 | x ^= x >> 1;
35 |
36 | /* 注意:在第 0 位之外的位,值不一定为 0 */
37 | return !(x & 1);
38 | }
39 |
--------------------------------------------------------------------------------
/exercise/ex2-66.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 练习题 2.66
3 | *
4 | * Generate mask indicating leftmost 1 in x. Assume w=32.
5 | * For example, 0xFF00 -> 0x8000, and 0x6000 -> 0x4000.
6 | * If x = 0, then return 0.
7 | *
8 | * int leftmost_one(unsigned x);
9 | *
10 | * 函数应该遵循位级整数编码规则,不过你可以假设数据类型 int 有 w=32 位。
11 | * 你的代码最多只能包含 15 个算术运算、位运算和逻辑运算。
12 | *
13 | * 提示:先将 x 转换成形如 [0...011...1] 的位向量。
14 | */
15 | int leftmost_one(unsigned x)
16 | {
17 | x |= x >> 1;
18 | x |= x >> 2;
19 | x |= x >> 4;
20 | x |= x >> 8;
21 | x |= x >> 16;
22 |
23 | /* 以上的代码将会把 x 转换成形如 [0...01...1] 的形式 */
24 | return x - (x >> 1);
25 | }
26 |
27 | /*
28 | * 在解决这道题的过程中,我想到了找到最右边的 1 的方法。
29 | *
30 | * 如果能够找到翻转一个位向量的方法,则可以找到最左边的 1 的方法。并且,这个方法
31 | * 可以不限制字长的长度。
32 | */
33 | int rightmost_one(unsigned x)
34 | {
35 | return ~((~x + 1) | x) + 1;
36 | }
37 |
--------------------------------------------------------------------------------
/exercise/ex2-68.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 练习题 2.68
3 | *
4 | * 写出具有如下原型的函数的代码
5 | *
6 | * Make with least signficant n bits set to 1
7 | * Example: n = 6 --> 0x3f, n = 17 --> 0x1FFFF
8 | * Assume 1 <= n <= w
9 | *
10 | * int lower_bits(int x, int n);
11 | *
12 | * 函数应该遵循位级整数编码规则。要注意 n = w 的情况
13 | */
14 |
15 | int lower_bits(int x, int n)
16 | {
17 | int r = 0;
18 | int s = n - 1;
19 |
20 | /* 1. 构造一个最低 n 位为 1 的数 */
21 | r = (1< 0x81234567, n=20 -> 0x45678123
7 | *
8 | * 函数应该遵循位级整数编码规则。要注意 n = 0 的情况。
9 | */
10 | unsigned rotate_right(unsigned x, int n)
11 | {
12 | int w = sizeof(int) << 3;
13 | /* 这里左移一位,解决 n = 0 的情况 */
14 | return ((x << (w-n-1)) << 1) + (x >> n);
15 | }
16 |
--------------------------------------------------------------------------------
/exercise/ex2-7.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 编译方法:
3 | * $ cc ex2-7.c ../show-bytes.c
4 | */
5 |
6 | #include
7 | #include
8 |
9 | typedef unsigned char *byte_pointer;
10 |
11 | extern void show_bytes(byte_pointer start, int len);
12 |
13 | int main(void)
14 | {
15 | const char *s = "abcdef";
16 | show_bytes((byte_pointer)s, strlen(s));
17 |
18 | return 0;
19 | }
20 |
--------------------------------------------------------------------------------
/exercise/ex2-70.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 练习题 2.70
3 | *
4 | * 写出具有如下原型的函数的代码:
5 | *
6 | * Return 1 when x can be represented as an n-bit, 2's complement
7 | * number; 0 otherwise
8 | * Assume 1 <= n <= w
9 | *
10 | * int fits_bits(int x, int n);
11 | *
12 | * 函数应该遵循位级整数编码规则。
13 | */
14 |
15 | /*
16 | * 如果我们需要观察一个数是否可以使用 n 位补码和表示。我们可以将这个数的低 n-1 位
17 | * 全部置零,然后观察 w...n 这些位。
18 | *
19 | * 对于正数来说,如果这些 w...n 这些位非零的话,则说明 n 位补码不足以表示这个数。
20 | * 对于负数来说,如果这些 w...n 这些位不是全 1 的话,则说明 n 位补码不足以表示这
21 | * 个数。
22 | */
23 | int fits_bits(int x, int n)
24 | {
25 | /* 1. 构造位 w...n 全 1,位 n-1...0 全 0 的位向量 */
26 | int s = ~((1 << (n - 1)) - 1);
27 |
28 | /* 2. 将 x 的低 n-1 位置零,其他位保留 */
29 | x &= s;
30 |
31 | /* 3. 此时,w...n 位是全 0 或者全 1,才可以用 n 位补码表示这个数 */
32 | return !x || x == s;
33 | }
34 |
--------------------------------------------------------------------------------
/exercise/ex2-71.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 练习题 2.71
3 | *
4 | * 你刚刚开始在一家公司工作,他们要实现一组过程来操作一个数据结构,要将 4 个有
5 | * 符号字节封装成一个 32 位 unsigned。一个字中的字节从 0(最低有效字节)编号到
6 | * 3(最高有效字节)。分配给你的任务是:为一个使用补码运算和算数右移的机器编写
7 | * 一个具有如下原型的函数:
8 | *
9 | * Declaration of data type where 4 bytes are packed into an unsigned
10 | *
11 | * typedef unsigned packed_t;
12 | *
13 | * Extract byte from word. Return as signed integer
14 | *
15 | * int xbyte(packed_t word, int bytenum);
16 | *
17 | * 也就是说,函数会抽取出指定的字节,再把它符号扩展为一个 32 位 int。你的前任
18 | * (因为水平不够高而被解雇了)编写了下面的代码:
19 | *
20 | * Failed attempt at xbyte
21 | * int xbyte(packed_t word, int bytenum)
22 | * {
23 | * return (word >> (bytenum << 3)) & 0xFF;
24 | * }
25 | *
26 | * A. 这段代码错在哪里?
27 | * B. 给出函数的正确实现,只能使用左右移位和一个减法。
28 | */
29 |
30 | /*
31 | * A. 这段代码不能处理截断的字节是负数的情况。
32 | */
33 |
34 | /*
35 | * B. 要实现这个函数,我们利用了在算数右移的机器上,无符号是零扩展的,而有符号数
36 | * 是符号扩展的这个特性。
37 | */
38 |
39 | typedef unsigned packed_t;
40 |
41 | int xbyte(packed_t word, int bytenum)
42 | {
43 | int shift_left = (3 - bytenum) << 3;
44 |
45 | return (word << shift_left) >> 24;
46 | }
47 |
--------------------------------------------------------------------------------
/exercise/ex2-72.c:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * 给你一个任务,写一个函数,将整数 val 复制到缓冲区 buf 中,但是只有缓冲区
4 | * buf 中,但是只有当缓冲区中有足够可用的空间时,才执行复制。
5 | *
6 | * 你写的代码如下:
7 | *
8 | * // Copy integer into buffer if space is available
9 | * // WARNING: The following code is buggy
10 | * void copy_int(int val, void *buf, int maxbytes) {
11 | * if (maxbytes-sizeof(val) >= 0)
12 | * memcpy(buf, (void *)&val, sizeof(val));
13 | * }
14 | *
15 | * 这段代码使用了库函数 memcpy。虽然在这里用这个函数有点刻意,因为我们只是想复
16 | * 制一个 int,但是说明了一种复制较大数据结构的常见方法。
17 | *
18 | * 你仔细地测试了这段代码后发现,哪怕 maxbytes 很小的时候,它也能把值复制到缓
19 | * 冲区中。
20 | *
21 | * A. 解释为什么代码中的条件测试总是成功。提示:sizeof 运算符返回类型为 size_t 的值。
22 | * B. 你该如何重写这个条件测试,使之工作正确。
23 | *
24 | */
25 |
26 | /*
27 | * A. 无论 maxbytes 等于多少,maxbytes-sizeof(int) >= 0 永远为真。因为有符号数和无符号
28 | * 数进行运算,最终会转换为无符号数。而无符号数的结果永远 >= 0。
29 | */
30 |
31 | /*
32 | * B. 修改的代码如下
33 | */
34 | void copy_int(int val, void *buf, int maxbytes)
35 | {
36 | if (maxbytes > 0 && maxbytes >= sizeof(int))
37 | memcpy(buf, (void *)&val, sizeof(val));
38 | }
39 |
--------------------------------------------------------------------------------
/exercise/ex2-74.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 练习题 2.74
3 | *
4 | * 写出具有如下原型的函数的代码:
5 | *
6 | * // Determine whether subtracting arguments will cause overflow
7 | * int tsub_ovf(int x, int y);
8 | *
9 | * 如果计算 x-y 导致溢出,这个函数就返回 1。
10 | *
11 | */
12 |
13 | #include /* INT_MIN */
14 |
15 | /* Determine whether subtracting arguments will cause overflow */
16 | int tsub_ovf(int x, int y)
17 | {
18 | int r = x - y;
19 | int pos_overflow = !(x & INT_MIN) && (y & INT_MIN) && (r & INT_MIN);
20 | int neg_overflow = (x & INT_MIN) && !(y & INT_MIN) && !(r & INT_MIN);
21 |
22 | return pos_overflow || neg_overflow;
23 | }
24 |
--------------------------------------------------------------------------------
/exercise/ex2-75.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 家庭作业 2.75
3 | *
4 | * 假设我们想要计算 x·y 的完整的 2w 位表示,其中,x 和 y 都是无符号数,并且运
5 | * 行在数据类型 unsigned 是 w 位的机器上。乘积的低 w 位能够用表达式 x·y 计算,
6 | * 所以,我们只需要一个具有下列原型的函数:
7 | *
8 | * unsigned unsigned_high_prod(unsigned x, unsigned y);
9 | *
10 | * 这个函数计算无符号变量 x·y 的高 w 位。
11 | * 我们使用一个具有下面原型的库函数:
12 | *
13 | * int signed_high_prod(int x, int y);
14 | *
15 | * 它计算在 x 和 y 采用补码形式的情况下,x·y 的高 w 位。编写代码调用这个过程,
16 | * 以实现用无符号数为参数的函数。验证你的解答的正确性。
17 | *
18 | * 提示:看看等式(2-18)的推导中,有符号乘积 x·y 和无符号乘积 x'·y' 之间的关
19 | * 系。
20 | */
21 | #include /* INT_MIN */
22 |
23 | unsigned unsigned_high_prod(unsigned x, unsigned y)
24 | {
25 | int x_highest_bit = (x & INT_MIN) == INT_MIN;
26 | int y_highest_bit = (y & INT_MIN) == INT_MIN;
27 |
28 | int result = signed_high_prod(x, y) + x * y_highest_bit + y * x_highest_bit;
29 | return result;
30 | }
31 |
--------------------------------------------------------------------------------
/exercise/ex2-76.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 练习题 2.76
3 | *
4 | * 假设我们有一个任务:生成一段代码,将整数变量 x 乘以不同的常数因子 K。为了提高
5 | * 效率,我们想只使用 +、- 和 << 运算。对于下列的 K 的值,写出执行乘法运算的C 表
6 | * 达式,每个表达式中最多使用 3 个运算。
7 | *
8 | * A. K=5
9 | * B. K=9
10 | * C. K=30
11 | * D. K=-56
12 | */
13 |
14 | #include
15 |
16 | int main(void)
17 | {
18 | int x = 6; /* 一个完美的数字 */
19 | int t;
20 |
21 | /* A. K=5: (1<<2) + 1 */
22 | t = (x << 2) + x;
23 | printf("%d * %d = %d\n", x, 5, t);
24 |
25 | /* B. K=9: (1<<3) + 1 */
26 | t = (x << 3) + x;
27 | printf("%d * %d = %d\n", x, 9, t);
28 |
29 | /* C. K=30: (1<<5) - (1<<1) */
30 | t = (x << 5) - (x << 1);
31 | printf("%d * %d = %d\n", x, 30, t);
32 |
33 | /* D. K=-56: (1<<3) - (1<<6) */
34 | t = (x << 3) - (x << 6);
35 | printf("%d * %d = %d\n", x, -56, t);
36 |
37 | return 0;
38 | }
39 |
--------------------------------------------------------------------------------
/exercise/ex2-77.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 家庭作业 2.77
3 | *
4 | * 写出具有如下原型的函数的代码:
5 | *
6 | * // Divide by power of two. Assume 0 <= k < w-1
7 | * int divide_power2(int x, int k);
8 | *
9 | * 该函数要用正确的舍入计算 x/2^k,并且应该遵循位级整数编码规则。
10 | */
11 |
12 | #include /* INT_MIN */
13 |
14 | /*
15 | * 对于整数除法,结果应该是向零舍入。而对于右移运算,结果是向下舍入。
16 | *
17 | * 对于 x >= 0 的情况,简单的右移运算的结果也是整数除法的结果。而对于 x < 0 的情
18 | * 况,因为结果是向下舍入的,而我们需要的是向上舍入的结果。这样子,当 x < 0 时,
19 | * 我们为 x 加上一个偏置值 (1<> k;
27 | }
28 |
--------------------------------------------------------------------------------
/exercise/ex2-78.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 家庭作业 2.78
3 | *
4 | * 写出函数 mul5div8 的代码,对于整数参数 x,计算 5*x/8,但是要遵循位级整数编
5 | * 码规则。你的代码计算 5*x 也会产生溢出。
6 | */
7 |
8 | #include
9 |
10 | int mul5div8(int x)
11 | {
12 | int sign = (x & INT_MIN) == INT_MIN;
13 | int bias = (7 + !sign) & 7;
14 | int t = (x << 2) + x;
15 | return (t + bias) >> 3;
16 | }
17 |
--------------------------------------------------------------------------------
/exercise/ex2-80.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 家庭作业 2.80
3 | *
4 | * 编写 C 表达式产生如下位模式,其中 a^n 表示符号 a 重复 n 次。假设一个 w 位的
5 | * 数据类型。你的代码可以包含对参数 m 和 n 的引用,它们分别表示 m 和 n 的值,但
6 | * 是不能使用表示 w 的参数。
7 | *
8 | * A. 1^(w-n)0^n
9 | * B. 0^(w-n-m)1^n0^m
10 | */
11 |
12 | /*
13 | * A. ~((1 << n) - 1)
14 | */
15 | int nlowest_zero(int n)
16 | {
17 | return ~((1 << n) - 1);
18 | }
19 |
20 | /*
21 | * B. ((1 << n) - 1) - ((1 << m) - 1) = (1 << n) - (1 << m)
22 | */
23 | int nlowestone_minus_mlowestone(int n, int m)
24 | {
25 | return (1 << (m + n)) - (1 << m);
26 | }
27 |
--------------------------------------------------------------------------------
/exercise/ex2-82.txt:
--------------------------------------------------------------------------------
1 | A. 对于串 Y,如果我们将小数点右移 k 位,得到的数字将是无穷串的开始 k 位。如果我们将
2 | Y 右移 2k 位,得到的数字将是无穷串的 k+1~2k 位。依次类推,我们可以得到下列的公式:
3 |
4 | S = Y * (2^-k + 2^-2k + ... + 2^-nk)
5 |
6 | 我们可以发现,括号内是一个等比数列。关于等比数列的性质和求值公式,请参考维基
7 | 百科的资料:http://zh.wikipedia.org/wiki/%E7%AD%89%E6%AF%94%E6%95%B0%E5%88%97
8 |
9 | 因为这个等比数列的公比是 0 <= q < 1,因此,根据维基百科的资料,我们的公式最
10 | 后可得:
11 |
12 | S = Y * (2^-k / (1 - 2^-k))
13 |
14 | B. (a) 001 => 1/7
15 | (b) 1001 => 3/5
16 | (c) 000111 => 1/9
17 |
--------------------------------------------------------------------------------
/exercise/ex2-84.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | 给定一个浮点格式,有 k 位指数和 n 位小数,对于小列数,写出阶码 E、尾数 M、
3 | 小数 f 和值 V 的公式。另外,请描述其位表示。
4 |
5 | A. 数 5.0。
6 | B. 能够被准确描述的最大奇整数。
7 | C. 最小的规格化数的倒数。
8 | ================================================================================
9 |
10 | A. 数 5.0
11 |
12 | E = 2, M = 1.25, f = 0.25, V = 1.25 x 2^2
13 |
14 | B. 能够被准确描述的最大奇整数
15 |
16 | 1. n <= 2^k-1, E = n, M = 2-§, V = -1^s x M x 2^n
17 | 低 n 位全 1,阶码域是 n+2^(k-1)-1,符号位是 1
18 | 2. n > 2^k-1, E=k-1, M = 2-§, V = -1^s x M x 2^k-1
19 | 低 2^k-1 位全 1,阶码域是 2^(k-1)+k-2,符号位是 1
20 |
21 | C. 最小的规格化的倒数
22 |
23 | E = 1-k, M = 1/(2-§), V = -1 x M x 2^1-k
24 | 小数部分的最高 k-1 是 1,小数部分是 1/(2-§)
25 |
--------------------------------------------------------------------------------
/exercise/ex2-85.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | 家庭作业 2.85 的解答,题目请看 00-topic.txt
3 | ================================================================================
4 |
5 | 0x0000 0000 0001 2^(-16445)
6 | 0x0001 8000 0000 2^(-16382)
7 | 0x7FFE FFFF FFFF 2^(16384)
8 |
--------------------------------------------------------------------------------
/exercise/ex2-86.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | 家庭作业 2.86 的解答,题目请看 00-topic.txt
3 | ================================================================================
4 |
5 | 0x8000 0 -63 -
6 | 0x3F01 257/256 0 257×2^(-8)
7 | 0x4700 1 8 -
8 | 0x00FF 255/256 -62 255×2^(-70)
9 | 0xFF00 - - -
10 | 0x3AA0 13/8 -5 13×2^(-8)
11 |
--------------------------------------------------------------------------------
/exercise/ex2-87.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | 家庭作业 2.87 的解答,题目请看 00-topic.txt
3 | ================================================================================
4 |
5 | 向 +oo 舍入的舍入方向为数轴正向,即舍入值>=原始值。向 +oo 摄入又称向上舍入。
6 |
7 | 208 0 1110 1010 208
8 |
9 | -7/(2^10) 1 0000 0111 -7/(2^10)
10 |
11 | 5/(2^17) 0 0000 0001 1/(2^10)
12 |
13 | -4096 1 1110 1111 -248
14 |
15 | 768 0 1111 0000 +∞
16 |
--------------------------------------------------------------------------------
/exercise/ex2-88.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | 家庭作业 2.88 的解答,题目请看 00-topic.txt
3 | ================================================================================
4 |
5 | A. 0x20001
6 | B. 1
7 | C. dx:1, dy: 1e10, dz: -1e10 (浮点运算无结合性)
8 | D. INT_MAX
9 | E. 1
10 |
--------------------------------------------------------------------------------
/exercise/ex2-90.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | 大约在公元前 250 年,希腊数学家阿基米德证明了 223/71 < PI < 22/7。如果当时
3 | 有一台计算机和标准库 ,他就能够确定 n 的单精度浮点近似值的十六进制
4 | 表示为 0x40490FDB。当然,所有的这些都只是近似值,因为 PI 不是有理数。
5 |
6 | A. 这个浮点值表示的二进制小数是多少?
7 | B. 22/7 的二进制小数表示是什么?提示:参见家庭作业 2.82。
8 | C. 这两个 22/7 的近似值从哪一位(相对于二进制小数点)开始不同的?
9 | ================================================================================
10 |
11 | 我们先将 PI 的十六进制的近似值用二进制表示出来:
12 |
13 | 0100 0000 0100 1001 0000 1111 1101 1011
14 |
15 | 我们在这里标注出 PI 的符号位,阶码位和小数位:
16 |
17 | 0 | 100 0000 0 | 100 1001 0000 1111 1101 1011
18 | s e M
19 |
20 | A. 这个浮点值的表示的二进制小数是多少?
21 |
22 | ==> 1.100 1001 0000 1111 1101 1011
23 |
24 | B. 22/7 的二进制小数表示是什么?提示:参见家庭作业 2.82。
25 |
26 | ==> 1.1001 001 001...
27 |
28 | C. 这两个 22/7 的近似值从哪一位(相对于二进制小数点)开始不同的?
29 |
30 | ==> 从小数点右边的第 10 位开始不同。
31 |
--------------------------------------------------------------------------------
/exercise/ex2-92.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 家庭作业 2.92
3 | * mofaph@gmail.com
4 | *
5 | * 遵循位级浮点编码规则,实现具有如下原型的函数:
6 | *
7 | * // Compute -f. If f is Nan, then return f.
8 | * float_bits float_absval(float_bits f);
9 | *
10 | * 对于浮点数 f,这个函数计算 -f。如果 f 是 NaN,你的函数应该简单地返回 f。测试你
11 | * 的函数,对参数 f 可以取的所有 2^32 个值求值,将结果与你使用机器的浮点运算得到
12 | * 的结果相比较。
13 | */
14 |
15 | typedef unsigned float_bits;
16 |
17 | /* Compute -f. If f is NaN, then return f */
18 | float_bits float_negate(float_bits f)
19 | {
20 | unsigned sign = f >> 31;
21 | unsigned exp = f >> 23 & 0xFF;
22 | unsigned frac = f & 0x7FFFFF;
23 |
24 | if (exp == 0xFF && frac != 0) /* NaN */
25 | return f;
26 | return (~sign << 31) | (exp << 23) | frac;
27 | }
28 |
--------------------------------------------------------------------------------
/exercise/ex3-34.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 练习题 3.34
3 | */
4 |
5 | int rfun(unsigned x)
6 | {
7 | if (!x)
8 | return 0;
9 | unsigned nx = x >> 1;
10 | int rv = rfun(nx);
11 | return rv + (x & 1);
12 | }
13 |
14 | #include
15 |
16 | int main(void)
17 | {
18 | int x = 0x73;
19 | int n = rfun(x);
20 |
21 | printf("0x%X: %d\n", x, n);
22 |
23 | return 0;
24 | }
25 |
--------------------------------------------------------------------------------
/exercise/ex3-54.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 家庭作业 3.54
3 | */
4 |
5 | int decode2(int x, int y, int z)
6 | {
7 | int t = (z - y) & 0x7FFF;
8 | return (x ^ t) * t;
9 | }
10 |
--------------------------------------------------------------------------------
/exercise/ex3-56.txt:
--------------------------------------------------------------------------------
1 | ====
2 | 3.56
3 | ====
4 |
5 | A. esi: x
6 | ebx: n
7 | edi: result
8 | edx: mask
9 |
10 | B. result: 0x55555555
11 | mask: 0x80000000
12 |
13 | C. mask != 0
14 |
15 | D. mask = (unsigned)mask >> (n&0xFF)
16 |
17 | E. result ^= x & mask
18 |
19 | ================================================================================
20 | int loop(int x, int n)
21 | {
22 | int result = 0x55555555;
23 | int mask;
24 | for (mask = 0x80000000; mask != 0; mask = (unsigned)mask & (n&0xFF))
25 | result ^= x & mask;
26 | return result;
27 | }
28 | ================================================================================
29 |
--------------------------------------------------------------------------------
/exercise/ex3-57.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 3.57
3 | *
4 | * 参考链接:
5 | *
6 | * http://book.douban.com/annotation/20427266/
7 | */
8 |
9 | /*
10 | * 在条件传送中,既然不能对数值为 0 的地址取值。通过思维转换,那么就取数值 0 的地
11 | * 址和数值非 0 的地址。然后再通过这个指针取值
12 | */
13 | int cread_alt(int *xp)
14 | {
15 | int t = 0;
16 | return *(xp ? xp : &t);
17 | }
18 |
--------------------------------------------------------------------------------
/exercise/ex3-58.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 3.58
3 | */
4 |
5 | /* Enumberated type creates set of constants numbered 0 and upward */
6 | typedef enum {
7 | MODE_A,
8 | MODE_B,
9 | MODE_C,
10 | MODE_D,
11 | MODE_E
12 | } mode_t;
13 |
14 | int switch3(int *p1, int *p2, mode_t action)
15 | {
16 | int result = 0;
17 | switch (action) {
18 | case MODE_A:
19 | result = *p1;
20 | *p1 = *p2;
21 | break;
22 | case MODE_B:
23 | result = *p1 + *p2;
24 | *p2 = result;
25 | break;
26 | case MODE_C:
27 | *p2 = 15;
28 | result = *p1;
29 | break;
30 | case MODE_D:
31 | *p2 = *p1;
32 | case MODE_E:
33 | result = 17;
34 | default:
35 | break;
36 | }
37 | return result;
38 | }
39 |
--------------------------------------------------------------------------------
/exercise/ex3-59.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 3.59
3 | */
4 | int switch_prob(int x, int n)
5 | {
6 | int result = x;
7 |
8 | switch (n) {
9 | case 42:
10 | case 40:
11 | result = x << 3;
12 | break;
13 | case 41:
14 | result += 17;
15 | break;
16 | case 43:
17 | result = x >> 3;
18 | break;
19 | case 45:
20 | result = x * x + 17;
21 | break;
22 | case 44:
23 | result = 49 * x * x;
24 | break;
25 | default:
26 | result += 17;
27 | }
28 | return result;
29 | }
30 |
--------------------------------------------------------------------------------
/exercise/ex3-60.txt:
--------------------------------------------------------------------------------
1 | 3.60
2 |
3 | A. &A[i][j][k] = X_D + L(S·L·i + T·j + k)
4 | B. R = 44, S = 7, T = 9
5 |
--------------------------------------------------------------------------------
/exercise/ex3-61.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 3.61
3 | *
4 | * $ gcc -O2 -S ex3-61.c # 这样就不会使循环的值溢出到存储器了
5 | */
6 |
7 | /* Compute i,k of variable matrix product */
8 | int var_prod_ele(int n, int A[n][n], int B[n][n], int i, int k)
9 | {
10 | int j;
11 | int result = 0;
12 |
13 | void *Arow = (void *)&A[i][0];
14 | void *Bcol = (void *)&B[0][k];
15 |
16 | int N = 4 * n;
17 | for (j = 0; j < N; j += 4)
18 | result += *(int *)(Arow + j) * *(int *)(Bcol + N);
19 |
20 | return result;
21 | }
22 |
--------------------------------------------------------------------------------
/exercise/ex3-62.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 3.62
3 | */
4 |
5 | /*
6 | * A. M=16
7 | * B. i: edi, j: ecx
8 | * C. 如下所示
9 | */
10 | void transpose(int M, int A[M][M])
11 | {
12 | int i, j;
13 |
14 | for (i = 0; i < M; i++) {
15 | int *col = &A[0][i];
16 | for (j = 0; j < i; j++) {
17 | int t = A[i][j];
18 | A[i][j] = *col;
19 | col += M;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/exercise/ex3-63.txt:
--------------------------------------------------------------------------------
1 | 3.63
2 |
3 | #define E1(n) 3*n
4 | #define E2(n) 2*n-1
5 |
--------------------------------------------------------------------------------
/exercise/ex3-64.txt:
--------------------------------------------------------------------------------
1 | 3.64
2 |
3 | A. eax: result, ebx: s1.v, edx: s1.p
4 | B. ebp-4: s1, ebp-8: s2, ebp-12: y, ebp-16: &x, ebp-20: s2
5 | C. 将结构的各位成员,按从高到低地址压入栈中
6 | D. 在栈中的 retaddr+4 位置,分配一个指向结构的指针作为返回地址
7 |
--------------------------------------------------------------------------------
/exercise/ex3-65.txt:
--------------------------------------------------------------------------------
1 | 3.65
2 |
3 | A=2, B=8
4 |
5 | 将 x 看作是有 A 个元素的数组,每个元素是一个含有 B 个元素的数组。由于需要每个元
6 | 素对齐,B 数组需要 16 个字节,所以 16 字节对齐。
7 |
--------------------------------------------------------------------------------
/exercise/ex3-66.txt:
--------------------------------------------------------------------------------
1 | 3.66
2 |
3 | A. CNT=7
4 | B. struct a_struct { int idx; int x[6]; };
5 |
6 | 这里要注意的是,生成的汇编代码中使用了一个技巧。这样就不容易看出来地址间的运算关
7 | 系了:
8 |
9 | 10 add 0x4(%ecx,%ebx,1), %edx ; memory[bp+28i+4] + 7i -> edx
10 | 13 mov %eax, 0x(%ecx,%edx,4) ; eax -> memory[bp+4*edx+8]
11 |
12 | 我们把 10 行的 edx 的值,带入 13 行中,可以得到:
13 |
14 | bp + 4 + 4 + 4*? + 28i
15 |
16 | 而在前面的第 10 行,我们其实已经取出了 idx 的值了:
17 |
18 | 10 add 0x4(%ecx,%ebx,1), %edx ; memory[bp+4 + 28i]
19 |
20 | 汇编代码在 bp+4+28i 的地址处取出 4 个字节的值,然后又在 bp+4+28i + 4 + 4*? 的地
21 | 址处写入一个值(这个值就是 n)。通过观察,我们就可以知道这个地址寻址的规律了:
22 | a_struct 前面有 4 个字节需要跳过,然后才到数组的寻址,而这个数组的每个元素也是 4
23 | 个字节的。
24 |
--------------------------------------------------------------------------------
/exercise/ex3-67.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 3.67
3 | *
4 | * mofaph@gmail.com
5 | */
6 |
7 | union ele {
8 | struct {
9 | int *p;
10 | int x;
11 | } e1;
12 |
13 | struct {
14 | int y;
15 | union ele *next;
16 | } e2;
17 | };
18 |
19 | /*
20 | * A. e1.p: 0, e1.x: 4, e2.y: 0, e2.next = 4
21 | * B. 8 个字节
22 | * C. 填写的缺失代码如下
23 | */
24 | void proc(union ele *up)
25 | {
26 | up->next->x = *(up->next->p) - up->y;
27 | }
28 |
--------------------------------------------------------------------------------
/exercise/ex3-68.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 3.68
3 | *
4 | * mofaph@gmail.com
5 | */
6 |
7 | #include
8 |
9 | #define MAX_INPUT 5 /* 以小一点的数字,使问题可以方便地出现(如果有的话) */
10 |
11 | int good_echo(void)
12 | {
13 | char s[MAX_INPUT];
14 | char *ret;
15 |
16 | ret = fgets(s, sizeof(s), stdin);
17 | if (ret == NULL) {
18 | if (!feof(stdin)) /* 输入错误 */
19 | return -1;
20 | goto done; /* 输入了 EOF */
21 | }
22 |
23 | int out;
24 | out = fputs(s, stdout);
25 | if (out == EOF)
26 | return -1; /* 输出错误 */
27 |
28 | done:
29 | return 0;
30 | }
31 |
--------------------------------------------------------------------------------
/exercise/ex3-69.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 3.69
3 | *
4 | * $ cc -m64 -S ex3-69.c # 使用 -m64 生成 64 位代码
5 | *
6 | * mofaph@gmail.com
7 | */
8 |
9 | typedef struct ELE *tree_ptr;
10 |
11 | struct ELE {
12 | tree_ptr left;
13 | tree_ptr right;
14 | long val;
15 | };
16 |
17 | /*
18 | * 这个函数用于找到二叉树的左子树的第一个叶子节点的 val
19 | *
20 | * o
21 | * / \
22 | * o o
23 | * / \ / \
24 | * o o o o
25 | * ^
26 | * |
27 | * 找到这个节点的值
28 | */
29 | long trace(tree_ptr tp)
30 | {
31 | long node = 0;
32 |
33 | while (tp) {
34 | node = tp->val;
35 | tp = tp->left;
36 | }
37 |
38 | return node;
39 | }
40 |
--------------------------------------------------------------------------------
/exercise/ex3-70.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 3.70
3 | *
4 | * $ gcc -m64 -S ex3-70.c # 生成 64 位的汇编代码
5 | *
6 | * mofaph@gmail.com
7 | */
8 |
9 | typedef struct ELE *tree_ptr;
10 |
11 | struct ELE {
12 | tree_ptr left;
13 | tree_ptr right;
14 | long val;
15 | };
16 |
17 | /*
18 | * 递归计算二叉树中所有节点中的最小值
19 | */
20 | long traverse(tree_ptr tp)
21 | {
22 | if (!tp)
23 | return -1;
24 |
25 | long v = tp->val;
26 | long vleft = traverse(tp->left);
27 | long vright = traverse(tp->right);
28 |
29 | if (vright > vleft)
30 | vright = vleft;
31 | if (v > vright)
32 | v = vright;
33 |
34 | return v;
35 | }
36 |
--------------------------------------------------------------------------------
/exercise/ex7-10.txt:
--------------------------------------------------------------------------------
1 | 7.10
2 |
3 | mofaph@gmail.com
4 | --------------------------------------------------------------------------------
5 |
6 | A. gcc -static p.o libx.a
7 | B. gcc -static p.o libx.a liby.a libx.a
8 | C. x -> y -> z
9 | \--> x -> z
10 |
11 | gcc -static p.o libx.a liby.a libx.a libz.a
12 |
--------------------------------------------------------------------------------
/exercise/ex7-11.txt:
--------------------------------------------------------------------------------
1 | 7.11
2 |
3 | mofaph@gmail.com
4 | --------------------------------------------------------------------------------
5 |
6 | .bss
7 |
--------------------------------------------------------------------------------
/exercise/ex7-12.txt:
--------------------------------------------------------------------------------
1 | 7.12
2 |
3 | mofaph@gmail.com
4 | --------------------------------------------------------------------------------
5 |
6 | |------------------+-----------+-----------|
7 | | 图 7-10 中的符号 | 地址 | 值 |
8 | |------------------+-----------+-----------|
9 | | 15 | 0x80483c8 | 0x804945c |
10 | |------------------+-----------+-----------|
11 | | 16 | 0x80483d0 | 0x8049458 |
12 | |------------------+-----------+-----------|
13 | | 18 | 0x80483d8 | 0x8049548 |
14 | |------------------+-----------+-----------|
15 | | 18 | 0x80483dc | 0x8049458 |
16 | |------------------+-----------+-----------|
17 | | 23 | 0x80483e7 | 0x8049548 |
18 | |------------------+-----------+-----------|
19 |
--------------------------------------------------------------------------------
/exercise/ex7-13.txt:
--------------------------------------------------------------------------------
1 | 7.13
2 |
3 | mofaph@gmail.com
4 | --------------------------------------------------------------------------------
5 |
6 | A. 0xc R_386_PC32 p3
7 | 0x13 R_386_32 xp
8 | 0x15 R_386_PC32 p2
9 |
10 | B. 0x4 R_386_32 x
11 |
12 | 我们也可以使用 objdump 来帮助我们完成这道题目,假设有一个目标文件是 a.o,那么我
13 | 们可以这样查看它的重定位条目的信息:
14 |
15 | $ objdump -rs a.o
16 |
--------------------------------------------------------------------------------
/exercise/ex7-14.txt:
--------------------------------------------------------------------------------
1 | 7.14
2 |
3 | mofaph@gmail.com
4 | --------------------------------------------------------------------------------
5 |
6 | A. .text:
7 | 0x25 R_386_32 .text
8 | 0x11 R_386_32 .text
9 | 0x28 R_386_32 .text
10 | 0x28 R_386_32 .text
11 | 0x28 R_386_32 .text
12 |
13 | B. .rodata:
14 | 0x0 R_386_32 .rodata
15 | 0x4 R_386_32 .rodata
16 | 0x8 R_386_32 .rodata
17 | 0xc R_386_32 .rodata
18 | 0x10 R_386_32 .rodata
19 | 0x14 R_386_32 .rodata
20 |
21 | 也可以使用 objdump 来帮助分析:
22 |
23 | $ objdump -rs a.o
24 |
--------------------------------------------------------------------------------
/exercise/ex7-15.txt:
--------------------------------------------------------------------------------
1 | 7.15
2 |
3 | mofaph@gmail.com
4 | --------------------------------------------------------------------------------
5 |
6 | A. $ libs=$(find /{,usr/}lib -type f -name "libc.a" -o -name "libm.a")
7 | $ for lib in $lib; do printf "$lib: "; ar t $lib | wc -l; done
8 |
9 | B. $ gcc -O2 main.c swap.c -o t
10 | $ gcc -O2 -g main.c swap.c -o t2
11 | $ readelf -a t > t.elf
12 | $ readelf -a t2 > t2.elf
13 | $ diff -u t.elf t2.elf
14 |
15 | C. $ ldd $(which gcc)
16 | or
17 | $ readelf -a t | grep interp
18 |
--------------------------------------------------------------------------------
/exercise/ex7-7.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 7.7
3 | *
4 | * mofaph@gmail.com
5 | */
6 |
7 | /*
8 | * Solution 1
9 | */
10 |
11 | int x;
12 |
13 | void f()
14 | {
15 | x = 15213;
16 | }
17 |
18 | /*
19 | * Solution 2
20 | */
21 | double x;
22 | void f()
23 | {
24 | return;
25 | x = -0.0;
26 | }
27 |
28 | /*
29 | * Solution 3
30 | */
31 |
32 | /* double x; */
33 |
34 | void f()
35 | {
36 | /* x = -0.0; */
37 | }
38 |
--------------------------------------------------------------------------------
/exercise/ex7-8.txt:
--------------------------------------------------------------------------------
1 | 7.8
2 |
3 | mofaph@gmail.com
4 |
5 | A.
6 |
7 | a) REF(main.1) --> DEF(main.1)
8 | b) REF(main.2) --> DEF(main.2)
9 |
10 | B.
11 |
12 | a) REF(x.1) --> DEF(x.UNKNOWN)
13 | b) REF(x.2) --> DEF(x.UNKNOWN)
14 |
15 | C.
16 |
17 | a) REF(x.1) --> DEF(x.ERROR)
18 | b) REF(x.2) --> DEF(x.ERROR)
19 |
--------------------------------------------------------------------------------
/exercise/ex7-9.txt:
--------------------------------------------------------------------------------
1 | 7.9
2 |
3 | mofaph@gmail.com
4 | --------------------------------------------------------------------------------
5 |
6 | 这道习题我没能解决,因为我没有注意到 foo6.c 中的 main 是一个强符号。不过,幸好我
7 | 看了第一版的参考答案,幸好第一版也有这道题目,幸好我手里有这份参考答案。 :-)
8 |
9 | 要理解这道题目,我们需要知道 UNIX 链接器处理多重符号的 3 个规则:
10 |
11 | 1. 不允许有多个强符号
12 | 2. 如果同时有一个强符号和多个弱符号,选择强符号
13 | 3. 如果有多个弱符号,那么从这些弱符号中任选一个
14 |
15 | 在这道题中,foo6.c 中的符号 main 是强符号,bar6.c 中的 main 是弱符号。
16 |
17 | 在 bar6.c 中打印 main 时,链接器选择了强符号,也就是在 foo6.c 中的 main 函数。在
18 | 目标文件中,符号 main 的地址就是 main 函数的起始地址。
19 |
20 | 因此,在 bar6.c 中的打印语句中,将会打印 main 函数的第一个字节的值。在 IA32 中,
21 | 函数的第一条指令通常是压栈指令:
22 |
23 | pushl %ebp
24 |
25 | 这条指令的机器码就是 0x55。
26 |
27 | PS: 可以在下面给出的地址找到参考答案
28 |
29 | [1] resource/im/im/im.pdf
30 | [2] ftp://202.120.40.101/Courses/Computer_Architecture/csapp.cs.cmu.edu/im/im/im.pdf
31 |
--------------------------------------------------------------------------------
/exercise/ex8-10.txt:
--------------------------------------------------------------------------------
1 | 8.10
2 |
3 | mofaph@gmail.com
4 | --------------------------------------------------------------------------------
5 |
6 | A. 调用一次,返回两次。
7 |
8 | fork
9 |
10 | B. 调用一次,从不返回。
11 |
12 | longjmp execve
13 |
14 | C. 调用一次,返回一次或者多次。
15 |
16 | setjmp
17 |
--------------------------------------------------------------------------------
/exercise/ex8-11.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 8.11
3 | *
4 | * 这个程序会输出多少个“hello”输出行?
5 | *
6 | * unix> gcc -I../common ex8-11.c ../common/csapp.c -lpthread
7 | * #4
8 | */
9 |
10 | #include "csapp.h"
11 |
12 | /*
13 | * .------------------------
14 | * |
15 | * |
16 | * |
17 | * .-----------.------------------------
18 | * |
19 | * |
20 | * | .------------------------
21 | * | |
22 | * | |
23 | * | |
24 | * .-----------.------------------------
25 | * fork fork
26 | * i=0 i=1
27 | */
28 | int main()
29 | {
30 | int i;
31 |
32 | for (i = 0; i < 2; i++)
33 | Fork();
34 | printf("hello\n");
35 | exit(0);
36 | }
37 |
--------------------------------------------------------------------------------
/exercise/ex8-12.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 8.12
3 | *
4 | * 这个程序会输出多少个“hello”输出行?
5 | *
6 | * unix> gcc -I../common ex8-12.c ../common/csapp.c -lpthread
7 | * #8
8 | */
9 |
10 | #include "csapp.h"
11 |
12 | void doit()
13 | {
14 | Fork();
15 | Fork();
16 | printf("hello\n");
17 | return;
18 | }
19 |
20 | int main()
21 | {
22 | doit();
23 | printf("hello\n");
24 | return;
25 | }
26 |
--------------------------------------------------------------------------------
/exercise/ex8-13.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 8.13
3 | *
4 | * 下面程序的一种可能的输出是什么?
5 | *
6 | * unix> gcc -I../common ex8-13.c ../common/csapp.c -lpthread
7 | *
8 | * 父进程先运行:
9 | * 4
10 | * 3
11 | * 2
12 | *
13 | * 子进程先运行:
14 | * 2
15 | * 4
16 | * 3
17 | *
18 | * 创建进程失败:
19 | * 4
20 | * 3
21 | */
22 |
23 | #include "csapp.h"
24 |
25 | int main()
26 | {
27 | int x = 3;
28 |
29 | if (Fork() != 0)
30 | printf("x=%d\n", ++x);
31 |
32 | printf("x=%d\n", --x);
33 | exit(0);
34 | }
35 |
--------------------------------------------------------------------------------
/exercise/ex8-14.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 8.14
3 | *
4 | * 下面这个程序会输出多少个“hello”输出行?
5 | *
6 | * unix> gcc -I../common ex8-14.c ../common/csapp.c -lpthread
7 | *
8 | * 第一个 Fork() 成功,第二个 Fork() 失败: 1
9 | * 第一个 Fork() 成功,第二个 Fork() 成功: 3
10 | * 第一个 Fork() 失败: 0
11 | */
12 |
13 | #include "csapp.h"
14 |
15 | void doit()
16 | {
17 | if (Fork() == 0) {
18 | Fork();
19 | printf("hello\n");
20 | exit(0);
21 | }
22 | return;
23 | }
24 |
25 | int main()
26 | {
27 | doit();
28 | printf("hello\n");
29 | exit(0);
30 | }
31 |
--------------------------------------------------------------------------------
/exercise/ex8-15.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 8.15
3 | *
4 | * 下面这个程序会输出多少个“hello”输出行?
5 | *
6 | * unix> gcc -I../common ex8-15.c ../common/csapp.c -lpthread
7 | *
8 | * 第一个 Fork 失败: 0
9 | * 第一个 Fork 成功,第二个 Fork 失败: 1
10 | * 第一个 Fork 成功,第二个 Fork 成功: 5
11 | */
12 |
13 | #include "csapp.h"
14 |
15 | void doit()
16 | {
17 | if (Fork() == 0) {
18 | Fork();
19 | printf("hello\n");
20 | return;
21 | }
22 | return;
23 | }
24 |
25 | int main()
26 | {
27 | doit();
28 | printf("hello\n");
29 | exit(0);
30 | }
31 |
--------------------------------------------------------------------------------
/exercise/ex8-16.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 8.16
3 | *
4 | * unix> gcc -I../common ex8-16.c ../common/csapp.c -lpthread
5 | * counter = 2
6 | */
7 |
8 | #include "csapp.h"
9 |
10 | int counter = 1;
11 |
12 | int main()
13 | {
14 | if (fork() == 0) {
15 | counter--;
16 | exit(0);
17 | } else {
18 | Wait(NULL);
19 | printf("counter = %d\n", ++counter);
20 | }
21 |
22 | exit(0);
23 | }
24 |
--------------------------------------------------------------------------------
/exercise/ex8-17.txt:
--------------------------------------------------------------------------------
1 | 8.17
2 |
3 | mofaph@gmail.com
4 | --------------------------------------------------------------------------------
5 |
6 | fork() 失败:
7 | Hello
8 | 0
9 | Bye
10 |
11 | fork() 成功:
12 |
13 | 1. 父进程先运行
14 | Hello
15 | 0
16 | 1
17 | Bye
18 | 2
19 | Bye
20 |
21 | 2. 子进程先运行
22 | Hello
23 | 1
24 | Bye
25 | 0
26 | 2
27 | Bye
28 |
29 | 3. 子进程先运行,在它运行期间,内核调度父进程运行
30 | Hello
31 | 1
32 | 0
33 | Bye
34 | 2
35 | Bye
36 |
--------------------------------------------------------------------------------
/exercise/ex8-18.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 8.18
3 | *
4 | * mofaph@gmail.com
5 | *
6 | * unix> cc -I../common ex8-18.c ../common/csapp.c -lpthread
7 | *
8 | * 判断下面哪个输出是可能的。注意:atexit 函数以一个指向函数的指针为输入,并将它
9 | * 添加到函数列表中(初始为空),当 exit 函数被调用时,会调用该列表中的函数。
10 | *
11 | * A. 112002
12 | * B. 211020
13 | * C. 102120
14 | * D. 122001
15 | * E. 100212
16 | *
17 | * 可能的序列: A C E
18 | */
19 |
20 | #include "csapp.h"
21 |
22 | void end(void)
23 | {
24 | printf("2");
25 | }
26 |
27 | int main()
28 | {
29 | if (Fork() == 0)
30 | atexit(end);
31 | if (Fork() == 0)
32 | printf("0");
33 | else
34 | printf("1");
35 | exit(0);
36 | }
37 |
--------------------------------------------------------------------------------
/exercise/ex8-19.txt:
--------------------------------------------------------------------------------
1 | 8.19
2 |
3 | mofaph@gmail.com
4 | --------------------------------------------------------------------------------
5 |
6 | 2 的 n 次方
7 |
8 | 输出的 hello 行 = 2^n
9 |
--------------------------------------------------------------------------------
/exercise/ex8-2.c:
--------------------------------------------------------------------------------
1 | #include "csapp.h"
2 |
3 | int main()
4 | {
5 | int x = 1;
6 |
7 | if (Fork() == 0)
8 | printf("printf1: x=%d\n", ++x);
9 | printf("printf2: x=%d\n", --x);
10 | exit(0);
11 | }
12 |
--------------------------------------------------------------------------------
/exercise/ex8-21.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 8.21
3 | *
4 | * mofaph@gmail.com
5 | *
6 | * 下面程序可能的输出序列是什么?
7 | *
8 | * unix> cc ex8-21.c
9 | * unix> ./a.out
10 | *
11 | * 1. fork 失败: bc
12 | * 2. fork 成功
13 | * 2.1 子进程先运行: abc
14 | * 2.2 父进程先运行: bac
15 | */
16 |
17 | #include
18 | #include
19 |
20 | #include
21 | #include
22 | #include
23 |
24 | int main()
25 | {
26 | if (fork() == 0) {
27 | printf("a");
28 | exit(0);
29 | } else {
30 | printf("b");
31 | waitpid(-1, NULL, 0);
32 | }
33 | printf("c");
34 | exit(0);
35 | }
36 |
--------------------------------------------------------------------------------
/exercise/ex8-23.txt:
--------------------------------------------------------------------------------
1 | 8.23
2 |
3 | mofaph@gmail.com
4 | --------------------------------------------------------------------------------
5 |
6 | 当父进程处理一个信号时,内核就会阻塞这个信号。也就是说,第二个信号是未决信号,从
7 | 第三个信号开始,内核就会丢弃这个信号。
8 |
--------------------------------------------------------------------------------
/exercise/ex8-26/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile for ex8-26
2 |
3 | # mofaph@gmail.com
4 | # 2013-7-7
5 |
6 | CC = gcc
7 | CFLAGS = -Wall
8 |
9 | PROGRAM += t
10 | PROGRAM += t-job
11 |
12 | OBJS += ex8-26.o
13 | OBJS += random_fork.o
14 | OBJS += job.o
15 |
16 | TOBJS += t-job.o
17 |
18 | PHONY += all
19 | PHONY += clean
20 | PHONY += TAGS
21 |
22 | .PHONY: $(PHONY)
23 |
24 | all: $(PROGRAM)
25 |
26 | t: $(OBJS)
27 | $(CC) $(CFLAGS) $^ -o $@
28 |
29 | t-job: t-job.o job.o
30 | $(CC) $(CFLAGS) $^ -o $@
31 |
32 | ex8-26.o: shellex.c
33 | $(CC) $(CFLAGS) -c $< -o $@
34 |
35 | t-job.o: t-job.c job.h
36 | job.o: job.c job.h
37 |
38 | TAGS:
39 | find . -type f -name "*.[ch]" -print | xargs etags -
40 |
41 | clean:
42 | rm -f $(PROGRAM) $(OBJS) $(TOBJS)
43 |
--------------------------------------------------------------------------------
/exercise/ex8-3.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 8.3 -- code/ecf/waitprob0.c
3 | *
4 | * 列出下面程序所有可能的输出序列
5 | *
6 | * $ gcc -iquote../common ../common/csapp.c ex8-3.c -lpthread
7 | */
8 |
9 | #include
10 | #include
11 |
12 | #include "csapp.h"
13 |
14 | int main(void)
15 | {
16 | if (Fork() == 0) { /* child */
17 | printf("a");
18 | } else { /* parent */
19 | printf("b");
20 | waitpid(-1, NULL, 0);
21 | }
22 |
23 | printf("c");
24 | exit(0);
25 | }
26 |
--------------------------------------------------------------------------------
/exercise/ex8-5.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 8.5
3 | *
4 | * 编写一个 sleep 的包装函数,叫做 snooze,带有下面的接口
5 | *
6 | * unsigned int snooze(unsigned int secs);
7 | *
8 | * 除了 snooze 函数会打印出一条信息来描述进程实际休眠了多长时间外,它和 sleep 函
9 | * 数的行为完全一样:
10 | *
11 | * Slept for 4 of 5 secs.
12 | */
13 |
14 | #include
15 |
16 | #include
17 |
18 | unsigned int snooze(unsigned int secs)
19 | {
20 | unsigned sleep_secs;
21 |
22 | sleep_secs = sleep(secs);
23 |
24 | printf("Slept for %u of %u secs\n", secs - sleep_secs, secs);
25 | return sleep_secs;
26 | }
27 |
28 | int main(void)
29 | {
30 | snooze(3);
31 | return 0;
32 | }
33 |
--------------------------------------------------------------------------------
/exercise/ex8-6.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 8.6 -- p502
3 | *
4 | * 编写一个叫做 myecho 的程序,它打印出它的命令行参数和环境变量
5 | *
6 | * unix> cc ex8-6.c -o myecho
7 | */
8 |
9 | #include
10 |
11 | int main(int argc, char *argv[])
12 | {
13 | int i;
14 |
15 | printf("Command line arguments:\n");
16 | for (i = 0; i < argc; i++)
17 | printf("\targv[%d]: %s\n", i, argv[i]);
18 | printf("\n");
19 |
20 | printf("Environment variables:\n");
21 | extern char **environ;
22 | for (i = 0; environ[i] != NULL; i++)
23 | printf("\tenvp[%2d]: %s\n", i, environ[i]);
24 |
25 | return 0;
26 | }
27 |
--------------------------------------------------------------------------------
/exercise/ex8-8.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 练习题 8.8 下面这个程序的输出是什么?
3 | *
4 | * 这个程序打印“213”,这是卡尔基梅隆大学 CS:APP 课程的缩写名
5 | */
6 |
7 | #include /* printf() fflush() */
8 | #include /* exit() */
9 |
10 | #include /* pid_t */
11 | #include /* waitpid() */
12 | #include /* kill() signal() */
13 | #include /* fork() */
14 |
15 | pid_t pid;
16 | int counter = 2;
17 |
18 | void handler1(int sig)
19 | {
20 | counter = counter - 1;
21 | printf("%d", counter);
22 | fflush(stdout);
23 | exit(0);
24 | }
25 |
26 | int main()
27 | {
28 | signal(SIGUSR1, handler1);
29 |
30 | printf("%d", counter);
31 | fflush(stdout);
32 |
33 | if ((pid = fork()) == 0) { /* child */
34 | while (1) {};
35 | }
36 | kill(pid, SIGUSR1);
37 | waitpid(-1, NULL, 0);
38 | counter = counter + 1;
39 | printf("%d", counter);
40 | exit(0);
41 | }
42 |
--------------------------------------------------------------------------------
/exercise/ex8-9.txt:
--------------------------------------------------------------------------------
1 | 8.9
2 |
3 | mofaph@gmail.com
4 | --------------------------------------------------------------------------------
5 |
6 | |------+----------+----------|
7 | | 进程 | 开始时间 | 结束时间 |
8 | |------+----------+----------|
9 | | A | 5 | 7 |
10 | | B | 2 | 4 |
11 | | C | 3 | 6 |
12 | | D | 1 | 8 |
13 | |------+----------+----------|
14 |
15 | 对于每对进程,指明它们是否是并发地运行的:
16 |
17 | |--------+----------|
18 | | 进程对 | 并发地? |
19 | |--------+----------|
20 | | AB | N |
21 | |--------+----------|
22 | | AC | Y |
23 | |--------+----------|
24 | | AD | Y |
25 | |--------+----------|
26 | | BC | Y |
27 | |--------+----------|
28 | | BD | Y |
29 | |--------+----------|
30 | | CD | Y |
31 | |--------+----------|
32 |
--------------------------------------------------------------------------------
/exercise/ex9-14.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 9.14
3 | *
4 | * 假设有一个输入文件 hello.txt,由字符串“Hello, world!\n”组成,编写一个 C 程序,
5 | * 使用 mmap 将 hello.txt 的内容改为“Jello, world!\n”。
6 | *
7 | * unix> gcc -Wall ex9-14.c t9-14.c
8 | *
9 | * mofaph@gmail.com
10 | */
11 |
12 | #include
13 |
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | int modify_file_using_mmap(int fd)
20 | {
21 | struct stat st;
22 | int ret = fstat(fd, &st);
23 | if (ret) {
24 | perror("fstat");
25 | return -1;
26 | }
27 |
28 | void *map_addr = mmap(NULL, st.st_size, PROT_WRITE, MAP_SHARED, fd, 0);
29 | if (map_addr == MAP_FAILED) {
30 | perror("mmap");
31 | return -1;
32 | }
33 |
34 | char *buf = map_addr;
35 | *buf = 'J';
36 |
37 | return 0;
38 | }
39 |
--------------------------------------------------------------------------------
/exercise/ex9-20/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile for ex9-20
2 |
3 | # mofaph@gmail.com
4 | # 2013-6-30
5 |
6 | CC = gcc
7 | CFLAGS = -Wall
8 |
9 | OBJS += ex9-20.o
10 | OBJS += t9-20.o
11 | OBJS += t-malloc.o
12 |
13 | PHONY += clean
14 | PHONY += all
15 | PHONY += TAGS
16 | PHONY += ex9-20
17 | PHONY += tm
18 |
19 | .PHONY: $(PHONY)
20 |
21 | all: ex9-20 tm
22 |
23 | TAGS:
24 | rm -f TAGS
25 | find . \( -type d -name .git -prune \) -o \( -type f -name "*.[ch]" \) | xargs etags -
26 |
27 | ex9-20: ex9-20.o t9-20.o
28 | $(CC) $(CFLAGS) $^ -o $@
29 |
30 | tm: t-malloc.o
31 | $(CC) $(CFLAGS) $^ -o $@
32 |
33 | clean:
34 | rm -f $(OBJS) ex9-20 tm TAGS
35 |
--------------------------------------------------------------------------------
/exercise/ex9-20/t-malloc.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #ifndef MAX_ITEM
4 | # define MAX_ITEM (1<<17)
5 | #endif
6 |
7 | int main(void)
8 | {
9 | int i;
10 | char *buf[MAX_ITEM];
11 | for (i = 1; i < MAX_ITEM; i++) {
12 | buf[i] = malloc(i);
13 | }
14 | for (i = 1; i < MAX_ITEM; i++) {
15 | free(buf[i]);
16 | }
17 |
18 | return 0;
19 | }
20 |
--------------------------------------------------------------------------------
/exercise/ex9-20/t2.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | int main(void)
5 | {
6 | struct free_block {
7 | char *addr;
8 | long size;
9 | };
10 |
11 | struct free_block *s, *e;
12 | long s1 = 0x8040a0a0;
13 | long s2 = s1 + 9*sizeof(struct free_block);
14 |
15 | s = (struct free_block *)s1;
16 | e = (struct free_block *)s2;
17 | printf("e: %p, s: %p, e-s: %d\n", e, s, e-s);
18 |
19 | return 0;
20 | }
21 |
--------------------------------------------------------------------------------
/exercise/ex9-20/t3.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int main(void)
4 | {
5 | char s[10];
6 | do {
7 | printf("Input: ");
8 | scanf("%s", s);
9 | printf("Output: %s\n", s);
10 |
11 | } while (s[0] != 'q');
12 |
13 | return 0;
14 | }
15 |
--------------------------------------------------------------------------------
/exercise/ex9-20/t9-20.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 9.20 -- test driver
3 | *
4 | * mofaph@gmail.com
5 | * 2013-6-28
6 | *
7 | * unix> cc -Wall ex9-20.c t9-20.c -o ex9-20
8 | * unix> ./ex9-20
9 | */
10 |
11 | #include
12 |
13 | extern int mo_init(void);
14 | extern void mo_free(void *bp);
15 | extern void *mo_malloc(size_t size);
16 |
17 | #ifndef MAX_ITEM
18 | # define MAX_ITEM (1<<17)
19 | #endif
20 |
21 | int main(void)
22 | {
23 | if (mo_init() < 0)
24 | return -1;
25 |
26 | int i;
27 | char *buf[MAX_ITEM];
28 | for (i = 1; i < MAX_ITEM; i++) {
29 | buf[i] = mo_malloc(i);
30 | }
31 | for (i = 1; i < MAX_ITEM; i++) {
32 | mo_free(buf[i]);
33 | }
34 |
35 | return 0;
36 | }
37 |
--------------------------------------------------------------------------------
/exercise/ex9-8.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 9.8
3 | *
4 | * 为 9.9.12 节中描述的简单分配器实现一个 find_fit 函数
5 | *
6 | * static void *find_fit(size_t asize);
7 | *
8 | * 你的解答应该对隐式空闲链表执行首次适配搜索。
9 | */
10 |
11 | static void *find_fit(size_t asize)
12 | {
13 | char *fit;
14 |
15 | for (fit = NEXT_BLKP(heap_listp);
16 | GET_SIZE(fit) > 0;
17 | fit = NEXT_BLKP(fit)) {
18 | if (GET_ALLOC(fit) && GET_SIZE(fit) >= asize)
19 | return (void *)fit;
20 | }
21 |
22 | return NULL;
23 | }
24 |
--------------------------------------------------------------------------------
/exercise/ex9-9.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 9.9
3 | *
4 | * 为示例的分配器编写一个 place 函数。
5 | *
6 | * static void place(void *bp, size_t asize);
7 | *
8 | * 你的解答应该将请求块放置在空闲块的位置,只有当剩余部分的大小等于或者超出最小块
9 | * 的大小时,才进行分割。
10 | */
11 |
12 | static void place(void *bp, size_t size)
13 | {
14 | size_t block_size = GET_SIZE(bp);
15 | size_t reserve_size = block_size - size;
16 |
17 | if (reserve_size < WSIZE) {
18 | PUT(HDRP(bp), PACK(block_size, 1));
19 | PUT(FTRP(bp), PACK(block_size, 1));
20 | } else if (WSIZE <= reserve_size && reserve_size < block_size) {
21 | PUT(HDRP(bp), PACK(size, 1));
22 | PUT(FTRP(bp), PACK(size, 1));
23 |
24 | PUT(HDRP(NEXT_BLKP(bp)), PACK(reserve_size, 0));
25 | PUT(FTRP(NEXT_BLKP(bp)), PACK(reserve_size, 0));
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/exercise/t2-59.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 2.59
3 | *
4 | * mofaph@gmail.com
5 | * 2013-12-17
6 | *
7 | * unix> cc -Wall ex2-59.c t2-59.c -o ex2-59
8 | */
9 |
10 | #include
11 |
12 | extern int combine_word(unsigned x, unsigned y);
13 |
14 | int main(void)
15 | {
16 | int x = 0x89ABCDEF;
17 | int y = 0x76543210;
18 | int z = combine_word(x, y);
19 |
20 | printf("x=0x%X, y=0x%X, combine_word=0x%X\n", x, y, z);
21 |
22 | return 0;
23 | }
24 |
--------------------------------------------------------------------------------
/exercise/t2-95.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 用于测试 ex2-95.c 的代码
3 | *
4 | * 编译:
5 | * $ cc ex2-89.c ex2-95.c t2-95.c
6 | *
7 | * 测试方法:
8 | * $ ./a.out
9 | * $ time ./a.out > t2-95.test
10 | *
11 | * mofaph@gmail.com
12 | */
13 |
14 | #include /* printf() */
15 | #include /* INT_MIN INT_MAX */
16 |
17 | typedef unsigned float_bits;
18 |
19 | extern unsigned f2u(float f); /* ex2-89.c */
20 | extern float_bits float_i2f(int i); /* ex2-95.c */
21 |
22 | int main(void)
23 | {
24 | float f;
25 | unsigned u, t;
26 |
27 | int i = INT_MIN;
28 | do {
29 | f = (float) i;
30 | u = f2u(f);
31 | t = float_i2f(i);
32 | if (u != t)
33 | printf("BAD: 0x%X, 0x%X, 0x%X\n", t, i, u);
34 | } while (i++ != INT_MAX);
35 |
36 | return 0;
37 | }
38 |
--------------------------------------------------------------------------------
/exercise/t2-96.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 测试家庭作业 2.96
3 | *
4 | * 编译:
5 | * $ cc ex2-89.c ex2-96.c t2-96.c
6 | *
7 | * 测试:
8 | * $ ./a.out
9 | *
10 | * mofaph@gmail.com
11 | */
12 |
13 | #include
14 | #include
15 |
16 | typedef unsigned float_bits;
17 |
18 | extern float u2f(unsigned u);
19 | extern int float_f2i(float_bits f); /* (int)f */
20 |
21 | int main(void)
22 | {
23 | float f;
24 | unsigned u, t;
25 |
26 | int i = INT_MIN;
27 | do {
28 | u = float_f2i(i);
29 | f = u2f(i);
30 | t = (int)f;
31 | if (u != t)
32 | printf("0x%08X: [GOOD: 0x%08X] [BAD: 0x%08X]\n", i, t, u);
33 | } while (i++ != INT_MAX);
34 |
35 | return 0;
36 | }
37 |
--------------------------------------------------------------------------------
/exercise/t3-68.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # 测试家庭作业 3.68
4 | # mofaph@gmail.com
5 |
6 | extern_file=ex3-68
7 | test_file=t3-68
8 | suffix=c
9 |
10 | # 自动生成一个测试文件
11 | cat <${test_file}.${suffix}
12 | /* NOTE!!! This is auto generate by a shell script */
13 |
14 | extern int good_echo(void);
15 |
16 | int main(void)
17 | {
18 | int ret;
19 | ret = good_echo();
20 | return ret;
21 | }
22 | EOF
23 |
24 | # 编译
25 | cc ${test_file}.${suffix} ${extern_file}.${suffix} -o ${test_file}
26 |
27 | # 产生数据以测试
28 | printf "hel\n" | ./${test_file} # 正常输入
29 | printf "\0" | ./${test_file} # 正常输入,但只有一个文件结束符
30 | printf "Barcelona" | ./${test_file} # 非法输入
31 |
32 | exit $?
33 |
--------------------------------------------------------------------------------
/exercise/t8-22.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 8.22
3 | *
4 | * unix> cc ex8-22.c t8-22.c
5 | */
6 |
7 | #include
8 |
9 | extern int mysystem(char *command); /* ex8-22.c */
10 |
11 | int main(int argc, char *argv[])
12 | {
13 | return mysystem(argv[1]);
14 | }
15 |
--------------------------------------------------------------------------------
/exercise/t8-25.c:
--------------------------------------------------------------------------------
1 | /*
2 | * test ex8-25.c
3 | *
4 | * unix> cc ex8-25.c t8-25.c
5 | */
6 |
7 | #include
8 |
9 | /* define in ex8-25.c */
10 | extern char *tfgets(char *s, int size, FILE *stream);
11 |
12 | int main(void)
13 | {
14 | char buf[BUFSIZ];
15 | char *bufp;
16 |
17 | bufp = tfgets(buf, sizeof(buf), stdin);
18 | printf("bufp: %p\n", bufp);
19 |
20 | return 0;
21 | }
22 |
--------------------------------------------------------------------------------
/exercise/t9-14.c:
--------------------------------------------------------------------------------
1 | /*
2 | * test ex9-14.c
3 | *
4 | * unix> gcc -Wall ex9-14.c t9-14.c
5 | *
6 | * mofaph@gmail.com
7 | */
8 |
9 | #include
10 | #include
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 |
17 | extern int modify_file_using_mmap(int fd); /* ex9-14.c */
18 |
19 | #define HELLO_FILE "t9-14.txt"
20 |
21 | int main(void)
22 | {
23 | int fd = open(HELLO_FILE, O_RDWR);
24 | if (fd < 0) {
25 | perror("open");
26 | return -1;
27 | }
28 |
29 | int ret = modify_file_using_mmap(fd);
30 | close(fd);
31 |
32 | return ret;
33 | }
34 |
--------------------------------------------------------------------------------
/exercise/t9-14.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # mofaph@gmail.com
4 |
5 | hello_file="hello.txt"
6 | t_914="t9-14.txt"
7 | out="t914"
8 |
9 | # Create test file
10 | printf "Hello, world\n" > $hello_file
11 | cp $hello_file $t_914
12 |
13 | # Compile and run
14 | cc -Wall ex9-14.c t9-14.c -o $out
15 | ./$out
16 |
17 | # Test the output
18 | if cmp -s $hello_file $t_914; then
19 | printf "FAILED: 9.14\n"
20 | fi
21 |
22 | # Test done, delete all the generated files
23 | rm -f $hello_file $t_914 $out
24 |
25 | exit $?
26 |
--------------------------------------------------------------------------------
/sample/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/sample/.gitignore
--------------------------------------------------------------------------------
/sample/ch02/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/sample/ch02/.gitignore
--------------------------------------------------------------------------------
/sample/ch02/show-bytes.c:
--------------------------------------------------------------------------------
1 | /*
2 | * p28 -- code/data/show-bytes.c
3 | *
4 | * 打印程序对象的字节表示。这段代码使用强制类型转换来规避类型系统。
5 | */
6 |
7 | #include
8 | #include
9 | #include
10 |
11 | typedef unsigned char *byte_pointer;
12 |
13 | void show_bytes(byte_pointer start, int len)
14 | {
15 | int i;
16 | for (i = 0; i < len; i++)
17 | printf(" %.2x", start[i]);
18 | printf("\n");
19 | }
20 |
21 | void show_int(int x)
22 | {
23 | show_bytes((byte_pointer) &x, sizeof(int));
24 | }
25 |
26 | void show_float(float x)
27 | {
28 | show_bytes((byte_pointer) &x, sizeof(float));
29 | }
30 |
31 | void show_pointer(void *x)
32 | {
33 | show_bytes((byte_pointer) &x, sizeof(void *));
34 | }
35 |
--------------------------------------------------------------------------------
/sample/ch03/buf-overflow.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | /* Sample implementation of library function gets() */
4 | char *our_gets(char *s)
5 | {
6 | int c;
7 | char *dest = s;
8 | int gotchar = 0; /* Has at least one character been read? */
9 | while ((c = getchar()) != '\n' && c != EOF) {
10 | *dest++ = c; /* No bounds checking! */
11 | gotchar = 1;
12 | }
13 | *dest++ = '\0'; /* Terminate string */
14 | if (c == EOF && !gotchar)
15 | return NULL; /* End of file or error */
16 | return s;
17 | }
18 |
19 | /* Read input line and write it back */
20 | void echo()
21 | {
22 | char buf[8]; /* Way too small */
23 | our_gets(buf);
24 | puts(buf);
25 | }
26 |
--------------------------------------------------------------------------------
/sample/ch03/code.c:
--------------------------------------------------------------------------------
1 | /*
2 | * p107
3 | *
4 | * 使用 GCC 产生汇编代码:
5 | * unix> gcc -O1 -S code.c
6 | *
7 | * 使用 GCC 产生目标代码文件:
8 | * unix> gcc -O1 -c code.c
9 | */
10 |
11 | int accum = 0;
12 |
13 | int sum(int x, int y)
14 | {
15 | int t = x + y;
16 | accum += t;
17 | return t;
18 | }
19 |
--------------------------------------------------------------------------------
/sample/ch03/main.c:
--------------------------------------------------------------------------------
1 | /*
2 | * p109
3 | *
4 | * unix> gcc -O1 -o prog code.o main.c
5 | */
6 |
7 | int main()
8 | {
9 | return sum(1, 3);
10 | }
11 |
--------------------------------------------------------------------------------
/sample/ch03/simple.c:
--------------------------------------------------------------------------------
1 | /*
2 | * p109
3 | *
4 | * unix> gcc -S -O1
5 | */
6 |
7 | int simple(int *xp, int y)
8 | {
9 | int t = *xp + y;
10 | *xp = t;
11 | return t;
12 | }
13 |
--------------------------------------------------------------------------------
/sample/ch03/simple_1.c:
--------------------------------------------------------------------------------
1 | /*
2 | * unix> gcc -O1 -S -m32 simple_1.c -o code32.s
3 | *
4 | * 或者
5 | *
6 | * unix> gcc -O1 -S -m64 simple_1.c -o code64.s
7 | */
8 |
9 | long int simple_1(long int *xp, long int y)
10 | {
11 | long int t = *xp + t;
12 | *xp = t;
13 | return t;
14 | }
15 |
--------------------------------------------------------------------------------
/sample/ch07/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/sample/ch07/.gitignore
--------------------------------------------------------------------------------
/sample/ch07/addvec.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 这个文件和 multvec.c 用于制作静态库 libvector.a
3 | *
4 | * unix> gcc -c addvec.c multvec.c
5 | * unix> ar rcs libvector.a addvec.o multvec.o
6 | */
7 |
8 | void addvec(int *x, int *y, int *z, int n)
9 | {
10 | int i;
11 |
12 | for (i = 0; i < n; i++)
13 | z[i] = x[i] + y[i];
14 | }
15 |
--------------------------------------------------------------------------------
/sample/ch07/bar1.c:
--------------------------------------------------------------------------------
1 | /*
2 | * bar1.c -- p455
3 | */
4 | int main()
5 | {
6 | return 0;
7 | }
8 |
--------------------------------------------------------------------------------
/sample/ch07/bar2.c:
--------------------------------------------------------------------------------
1 | /*
2 | * bar2.c -- p455
3 | */
4 | int x = 15213;
5 |
6 | void f()
7 | {
8 | }
9 |
--------------------------------------------------------------------------------
/sample/ch07/bar3.c:
--------------------------------------------------------------------------------
1 | /*
2 | * bar3.c -- p455
3 | */
4 | int x;
5 |
6 | void f()
7 | {
8 | x = 15212;
9 | }
10 |
--------------------------------------------------------------------------------
/sample/ch07/bar4.c:
--------------------------------------------------------------------------------
1 | /*
2 | * bar4.c -- p456
3 | */
4 |
5 | int x;
6 |
7 | void f()
8 | {
9 | x = 15212;
10 | }
11 |
--------------------------------------------------------------------------------
/sample/ch07/bar5.c:
--------------------------------------------------------------------------------
1 | /*
2 | * bar5.c -- p456
3 | */
4 |
5 | double x;
6 |
7 | void f()
8 | {
9 | x = -0.0;
10 | }
11 |
--------------------------------------------------------------------------------
/sample/ch07/foo1.c:
--------------------------------------------------------------------------------
1 | /*
2 | * foo1.c -- p455
3 | */
4 |
5 | int main()
6 | {
7 | return 0;
8 | }
9 |
--------------------------------------------------------------------------------
/sample/ch07/foo2.c:
--------------------------------------------------------------------------------
1 | /*
2 | * foo2.c -- p455
3 | */
4 | int x = 15213;
5 |
6 | int main()
7 | {
8 | return 0;
9 | }
10 |
--------------------------------------------------------------------------------
/sample/ch07/foo3.c:
--------------------------------------------------------------------------------
1 | /*
2 | * foo3.c -- p455~p456
3 | */
4 |
5 | #include
6 | void f(void);
7 |
8 | int x = 15213;
9 |
10 | int main()
11 | {
12 | f();
13 | printf("x = %d\n", x);
14 | return 0;
15 | }
16 |
--------------------------------------------------------------------------------
/sample/ch07/foo4.c:
--------------------------------------------------------------------------------
1 | /*
2 | * foo4.c -- p456
3 | */
4 |
5 | #include
6 |
7 | void f(void);
8 |
9 | int x;
10 |
11 | int main()
12 | {
13 | x = 15213;
14 | f();
15 | printf("x = %d\n", x);
16 | return 0;
17 | }
18 |
--------------------------------------------------------------------------------
/sample/ch07/foo5.c:
--------------------------------------------------------------------------------
1 | /*
2 | * foo5.c -- p456
3 | */
4 |
5 | #include
6 |
7 | void f(void);
8 |
9 | /*
10 | * 在一台 IA32/Linux 机器上,double 类型是 8 个字节,而 int 类型是 4 个字节。因此,
11 | * bar5.c 的第 6 行中的赋值 x=-0.0 将用负零的双精度浮点表示覆盖存储器中 x 和 y 的位置!
12 | *
13 | * 当我们怀疑有此类错误的时候,使用像 GCC 的 -fno-common 这样的选项调用链接器,这
14 | * 个选项会告诉链接器,在遇到多重定义的全局符号时,输出一条警告信息
15 | */
16 |
17 | int x = 15213;
18 | int y = 15212;
19 |
20 | int main()
21 | {
22 | f();
23 | printf("x = 0x%x, y = 0x%x\n", x, y);
24 | return 0;
25 | }
26 |
--------------------------------------------------------------------------------
/sample/ch07/linkerror.c:
--------------------------------------------------------------------------------
1 | /*
2 | * p454
3 | */
4 |
5 | void foo(void);
6 |
7 | int main(void)
8 | {
9 | foo();
10 | return 0;
11 | }
12 |
--------------------------------------------------------------------------------
/sample/ch07/main.c:
--------------------------------------------------------------------------------
1 | /*
2 | * p449
3 | */
4 |
5 | void swap();
6 |
7 | int buf[2] = {1, 2};
8 |
9 | int main()
10 | {
11 | swap();
12 | return 0;
13 | }
14 |
--------------------------------------------------------------------------------
/sample/ch07/main2.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 这个文件用于演示静态库的使用
3 | *
4 | * 在使用之前,我们需要生成 libvector.a
5 | *
6 | * unix> gcc -O2 -c main2.c
7 | * unix> gcc -static -o p2 main2.o ./libvector.a
8 | */
9 |
10 | #include
11 | #include "vector.h"
12 |
13 | int x[2] = {1, 2};
14 | int y[2] = {3, 4};
15 | int z[2];
16 |
17 | int main()
18 | {
19 | addvec(x, y, z, 2);
20 | printf("z = [%d %d]\n", z[0], z[1]);
21 | return 0;
22 | }
23 |
--------------------------------------------------------------------------------
/sample/ch07/multvec.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 这个文件用于制作 libvector.a 静态库,具体方法见 addvec.c
3 | */
4 |
5 | void multvec(int *x, int *y, int *z, int n)
6 | {
7 | int i;
8 |
9 | for (i = 0; i < n; i++)
10 | z[i] = x[i] * y[i];
11 | }
12 |
--------------------------------------------------------------------------------
/sample/ch07/swap.c:
--------------------------------------------------------------------------------
1 | /*
2 | * p449
3 | */
4 |
5 | extern int buf[];
6 |
7 | int *bufp0 = &buf[0];
8 | int *bufp1;
9 |
10 | void swap()
11 | {
12 | int temp;
13 |
14 | bufp1 = &buf[1];
15 | temp = *bufp0;
16 | *bufp0 = *bufp1;
17 | *bufp1 = temp;
18 | }
19 |
--------------------------------------------------------------------------------
/sample/ch07/vector.h:
--------------------------------------------------------------------------------
1 | extern void multvec(int *x, int *y, int *z, int n);
2 | extern void addvec(int *x, int *y, int *z, int n);
3 |
--------------------------------------------------------------------------------
/sample/ch08/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/sample/ch08/.gitignore
--------------------------------------------------------------------------------
/sample/ch08/alarm.c:
--------------------------------------------------------------------------------
1 | /*
2 | * p509 -- code/ecf/alarm.c
3 | *
4 | * 使用 alarm() 函数来调度周期性事件
5 | *
6 | * 这个程序安排自己被 SIGALRM 信号在 5 秒内每秒中断一次。当传送第 6 个 SIGALRM 信
7 | * 号时,它就终止。
8 | *
9 | * 注意:这里设置了一个信号处理函数,只要进程收到一个 SIGALRM 信号,就异步地调用
10 | * 该函数,中断 main 程序中的无限 while 循环
11 | *
12 | * $ gcc -I../../common alarm.c ../../common/csapp.c -lpthread
13 | */
14 |
15 | #include "csapp.h"
16 |
17 | void handler(int sig)
18 | {
19 | static int beeps = 0;
20 |
21 | printf("BEEP\n");
22 | if (++beeps < 5)
23 | Alarm(1); /* Next SIGALRM will be delivered in 1 second */
24 | else {
25 | printf("BOMP!\n");
26 | exit(0);
27 | }
28 | }
29 |
30 | int main()
31 | {
32 | Signal(SIGALRM, handler); /* Install SIGALRM handler */
33 | Alarm(1); /* Next SIGALRM will be delivered in 1s */
34 |
35 | while (1) {
36 | ; /* Signal handler returns control here each time */
37 | }
38 | exit(0);
39 | }
40 |
--------------------------------------------------------------------------------
/sample/ch08/fork.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 8.2
3 | *
4 | * A. 子进程的输出是什么?
5 | * B. 父进程的输出是什么?
6 | */
7 |
8 | #include "csapp.h"
9 |
10 | int main()
11 | {
12 | pid_t pid;
13 | int x = 1;
14 |
15 | pid = Fork();
16 | if (pid == 0) { /* child */
17 | printf("child: x=%d\n", ++x);
18 | exit(0);
19 | }
20 |
21 | /* parent */
22 | printf("parent: x=%d\n", --x);
23 | exit(0);
24 | }
25 |
--------------------------------------------------------------------------------
/sample/ch08/hello-asm.sa:
--------------------------------------------------------------------------------
1 | ;; p486
2 |
3 | ;; 下面的 C 代码等价于下面的汇编代码
4 |
5 | ;; int main()
6 | ;; {
7 | ;; write(1, "hello world\n", 13);
8 | ;; exit(0);
9 | ;; }
10 |
11 | .section .data
12 | string:
13 | .ascii "hello world\n"
14 | string_end:
15 | .equ len, string_end - string
16 |
17 | .section .text
18 | .global main
19 | main:
20 | ;; First, call write(1, "hello world\n", 13)
21 | movl $4, %eax ; System call number 4
22 | movl $1, %ebx ; stdout has descriptor 1
23 | movl $string, %ecx ; hello world string
24 | movl $len, %edx ; String length
25 | int $0x80 ; System call code
26 |
27 | ;; Next, call exit(0)
28 | movl $1, %eax ; System call number
29 | movl $0, %ebx ; Argument is 0
30 | int $0x80 ; System call code
31 |
--------------------------------------------------------------------------------
/sample/ch08/kill.c:
--------------------------------------------------------------------------------
1 | /*
2 | * p508 -- code/ecf/kill.c
3 | *
4 | * 父进程用 kill() 发送 SIGKILL 信号给它的子进程
5 | *
6 | * $ gcc -I../../common kill.c ../../common/csapp.c -lpthread
7 | */
8 |
9 | #include "csapp.h"
10 |
11 | int main()
12 | {
13 | pid_t pid;
14 |
15 | /* Child sleeps until SIGKILL signal received, then dies */
16 | if ((pid = Fork()) == 0) {
17 | Pause(); /* Wait for a signal to arrive */
18 | printf("control should never reach here!\n");
19 | exit(0);
20 | }
21 |
22 | /* Parent sends a SIGKILL signal to a child */
23 | Kill(pid, SIGKILL);
24 | exit(0);
25 | }
26 |
--------------------------------------------------------------------------------
/sample/ch08/restart.c:
--------------------------------------------------------------------------------
1 | /*
2 | * p523 -- code/ecf/restart.c
3 | *
4 | * 非本地跳转的另一个重要应用是使一个信号处理程序分支到一个特殊的代码位置,而不是
5 | * 返回到被信号到达中断了的指令的位置。
6 | *
7 | * 这个示例程序,在一个用户键入 ctrl-c 时,使用非本地跳转来重启到它自身
8 | *
9 | * 在程序第一次启动时,对 sigsetjmp() 的初始调用保存调用环境和信号的上下文(包括
10 | * 待处理的和被阻塞的信号向量)。随后,主函数进入一个无限处理循环。当用户键入
11 | * ctrl-c 时,外壳发送一个 SIGINT 信号给这个进程,该进程捕获这个信号。不是从信号
12 | * 处理程序返回,如果是这样信号处理程序会将控制返回给被中断的处理循环,反之,处理
13 | * 程序执行一个非本地跳转,回到主函数的开始处。
14 | *
15 | * unix> gcc -I../../common restart.c ../../common/csapp.c -lpthread
16 | */
17 |
18 | #include "csapp.h"
19 |
20 | sigjmp_buf buf;
21 |
22 | void handler(int sig)
23 | {
24 | siglongjmp(buf, 1);
25 | }
26 |
27 | int main()
28 | {
29 | Signal(SIGINT, handler);
30 |
31 | if (!sigsetjmp(buf, 1))
32 | printf("starting\n");
33 | else
34 | printf("restarting\n");
35 |
36 | while (1) {
37 | Sleep(1);
38 | printf("processing...\n");
39 | }
40 | exit(0);
41 | }
42 |
--------------------------------------------------------------------------------
/sample/ch08/sigint1.c:
--------------------------------------------------------------------------------
1 | /*
2 | * p510 -- code/ecf/sigint1.c
3 | *
4 | * 这个程序捕获用户在键盘上输入 Ctrl-C 时外壳发送的 SIGINT 信号。SIGINT 的默认行
5 | * 为是立刻终止该进程。在这个示例中,我们将默认行为修改为捕获信号,输出一条信息,
6 | * 然后终止该进程
7 | *
8 | * $ gcc -I../../common sigint1.c ../../common/csapp.c -lpthread
9 | */
10 |
11 | #include "csapp.h"
12 |
13 | void handler(int sig) /* SIGINT handler */
14 | {
15 | printf("Caught SIGINT\n");
16 | exit(0);
17 | }
18 |
19 | int main()
20 | {
21 | /* Install the SIGINT handler */
22 | if (signal(SIGINT, handler) == SIG_ERR)
23 | unix_error("signal error");
24 |
25 | pause(); /* Wait for the receipt of a signal */
26 |
27 | exit(0);
28 | }
29 |
--------------------------------------------------------------------------------
/sample/ch08/waitpid1.c:
--------------------------------------------------------------------------------
1 | /*
2 | * p498 -- code/ecf/waitpid1.c
3 | *
4 | * 使用 waitpid 函数不按照特定的顺序回收僵死子进程
5 | */
6 |
7 | #include "csapp.h"
8 | #define N 2
9 |
10 | int main(void)
11 | {
12 | int status, i;
13 | pid_t pid;
14 |
15 | /* Parent creates N children */
16 | for (i = 0; i < N; i++)
17 | if ((pid = Fork()) == 0) /* Child */
18 | exit(100+i);
19 |
20 | /* Parent reaps N children in no particular order */
21 | while ((pid = waitpid(-1, &status, 0)) > 0) {
22 | if (WIFEXITED(status))
23 | printf("child %d terminated normally with exit status=%d\n",
24 | pid, WEXITSTATUS(status));
25 | else
26 | printf("child %d terminated abnormally\n", pid);
27 | }
28 |
29 | /* The normal termination is if there are no more children */
30 | if (errno != ECHILD)
31 | unix_error("waitpid error");
32 |
33 | exit(0);
34 | }
35 |
--------------------------------------------------------------------------------
/sample/ch08/waitpid2.c:
--------------------------------------------------------------------------------
1 | /*
2 | * p498 -- code/ecf/waitpid2.c
3 | *
4 | * 使用 waitpid 按照创建子进程的顺序来回收僵死子进程
5 | */
6 |
7 | #include "csapp.h"
8 | #define N 2
9 |
10 | int main(void)
11 | {
12 | int status, i;
13 | pid_t pid[N], retpid;
14 |
15 | /* Parent creates N children */
16 | for (i = 0; i < N; i++)
17 | if ((pid[i] = Fork()) == 0) /* Child */
18 | exit(100+i);
19 |
20 | /* Parent reaps N children is order */
21 | i = 0;
22 | while ((retpid = waitpid(pid[i++], &status, 0)) > 0) {
23 | if (WIFEXITED(status))
24 | printf("child %d terminated normally with exit status=%d\n",
25 | retpid, WEXITSTATUS(status));
26 | else
27 | printf("child %d terminated abnormally\n", retpid);
28 | }
29 |
30 | /* The only normal termination is if there are no more children */
31 | if (errno != ECHILD)
32 | unix_error("waitpid error");
33 |
34 | exit(0);
35 | }
36 |
--------------------------------------------------------------------------------
/sample/ch09/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/sample/ch09/.gitignore
--------------------------------------------------------------------------------
/sample/ch09/mm-test.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | extern void mem_init(void);
4 | extern int mm_init(void);
5 | extern void mm_free(void *bp);
6 | extern void *mm_malloc(size_t size);
7 |
8 | int main(void)
9 | {
10 | mem_init();
11 | if (mm_init() < 0)
12 | return -1;
13 |
14 | char *buf = mm_malloc(1);
15 | printf("buf : %p\n", buf);
16 | if (buf)
17 | mm_free(buf);
18 |
19 | char *buf2 = mm_malloc(4);
20 | printf("buf2: %p\n", buf2);
21 | if (buf2)
22 | mm_free(buf2);
23 |
24 | char *buf3 = mm_malloc(8);
25 | printf("buf3: %p\n", buf3);
26 |
27 | char *buf4 = mm_malloc(12);
28 | printf("buf4: %p\n", buf4);
29 |
30 | if (buf3)
31 | mm_free(buf3);
32 | if (buf4)
33 | mm_free(buf4);
34 |
35 | buf = mm_malloc(4);
36 | printf("buf : %p\n", buf);
37 |
38 | buf2 = mm_malloc(9);
39 | printf("buf2: %p\n", buf2);
40 |
41 | if (buf)
42 | mm_free(buf);
43 | if (buf2)
44 | mm_free(buf2);
45 |
46 | return 0;
47 | }
48 |
--------------------------------------------------------------------------------
/sample/ch10/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/sample/ch10/.gitignore
--------------------------------------------------------------------------------
/sample/ch10/cpfile.c:
--------------------------------------------------------------------------------
1 | /*
2 | * p602
3 | *
4 | * 使用 RIO 函数一次一行地从标准输入拷贝一个文本文件到标准输出
5 | *
6 | * unix> cc -I../../common ../../common/csapp.c cpfile.c -lpthread
7 | */
8 |
9 | #include "csapp.h"
10 |
11 | int main(int argc, char *argv[])
12 | {
13 | int n;
14 | rio_t rio;
15 | char buf[MAXLINE];
16 |
17 | Rio_readinitb(&rio, STDIN_FILENO);
18 | while ((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0)
19 | Rio_writen(STDOUT_FILENO, buf, n);
20 | }
21 |
--------------------------------------------------------------------------------
/sample/ch10/cpstdin.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 使用 read/write 一次一个字节地从标准输入拷贝到标准输出
3 | *
4 | * $ cc -I../../common cpstdin.c ../../common/csapp.c -lpthread
5 | */
6 |
7 | #include "csapp.h"
8 |
9 | int main(void)
10 | {
11 | char c;
12 |
13 | while (Read(STDIN_FILENO, &c, 1) != 0)
14 | Write(STDOUT_FILENO, &c, 1);
15 |
16 | exit(0);
17 | }
18 |
--------------------------------------------------------------------------------
/sample/ch10/statcheck.c:
--------------------------------------------------------------------------------
1 | /*
2 | * 查询和处理一个文件的 st_mode 位
3 | *
4 | * $ cc -I../../common statcheck.c ../../common/csapp.c -lpthread
5 | */
6 |
7 | #include "csapp.h"
8 |
9 | int main(int argc, char **argv)
10 | {
11 | struct stat stat;
12 | char *type, *readok;
13 |
14 | Stat(argv[1], &stat);
15 |
16 | if (S_ISREG(stat.st_mode)) /* Determine file type */
17 | type = "regular";
18 | else if (S_ISDIR(stat.st_mode))
19 | type = "directory";
20 | else
21 | type = "other";
22 |
23 | if ((stat.st_mode & S_IRUSR)) /* Check read access */
24 | readok = "yes";
25 | else
26 | readok = "no";
27 |
28 | printf("type: %s, read: %s\n", type, readok);
29 | exit(0);
30 | }
31 |
--------------------------------------------------------------------------------
/sample/ch11/echo.c:
--------------------------------------------------------------------------------
1 | /*
2 | * p632
3 | *
4 | * 读和回送文本行的 echo 函数
5 | *
6 | * unix> cc -I../../common ../../common/csapp.c echoserveri.c echo.c -lpthread -o echod
7 | */
8 |
9 | #include "csapp.h"
10 |
11 | void echo(int connfd)
12 | {
13 | size_t n;
14 | char buf[MAXLINE];
15 | rio_t rio;
16 |
17 | Rio_readinitb(&rio, connfd);
18 | while ((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0) {
19 | printf("server received %d bytes\n", (int)n);
20 | Rio_writen(connfd, buf, n);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/sample/ch11/echoclient.c:
--------------------------------------------------------------------------------
1 | /*
2 | * p631
3 | *
4 | * echo 客户端的主程序
5 | *
6 | * unix> cc -I../../common ../../common/csapp.c echoclient.c -lpthread -o echoclient
7 | * unix> ./echoclient
8 | */
9 |
10 | #include "csapp.h"
11 |
12 | int main(int argc, char **argv)
13 | {
14 | int clientfd, port;
15 | char *host, buf[MAXLINE];
16 | rio_t rio;
17 |
18 | if (argc != 3) {
19 | fprintf(stderr, "usage: %s \n", argv[0]);
20 | exit(0);
21 | }
22 | host = argv[1];
23 | port = atoi(argv[2]);
24 |
25 | clientfd = Open_clientfd(host, port);
26 | Rio_readinitb(&rio, clientfd);
27 |
28 | while (Fgets(buf, MAXLINE, stdin) != NULL) {
29 | Rio_writen(clientfd, buf, strlen(buf));
30 | Rio_readlineb(&rio, buf, MAXLINE);
31 | Fputs(buf, stdout);
32 | }
33 |
34 | Close(clientfd);
35 | exit(0);
36 | }
37 |
--------------------------------------------------------------------------------
/sample/ch11/tiny/godzilla.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/sample/ch11/tiny/godzilla.gif
--------------------------------------------------------------------------------
/sample/ch11/tiny/godzilla.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vonzhou/CSAPP/b249d08e7fbc6c2bc19b0fec3595952522d45d52/sample/ch11/tiny/godzilla.jpg
--------------------------------------------------------------------------------
/sample/ch11/tiny/home.html:
--------------------------------------------------------------------------------
1 | Welcome to add.com
2 |
--------------------------------------------------------------------------------
/sample/ch12/echo_cnt.c:
--------------------------------------------------------------------------------
1 | /*
2 | * p675 -- code/conc/echo_cnt.c
3 | *
4 | * 从客户端接收的所有字节计数
5 | *
6 | * 下面的代码展示了一个从线程例程调用的初始化程序包的一般技术。
7 | */
8 |
9 | #include "csapp.h"
10 |
11 | static int byte_cnt; /* Byte counter */
12 | static sem_t mutex; /* and the mutex that protects it */
13 |
14 | static void init_echo_cnt(void)
15 | {
16 | Sem_init(&mutex, 0, 1);
17 | byte_cnt = 0;
18 | }
19 |
20 | void echo_cnt(int connfd)
21 | {
22 | int n;
23 | char buf[MAXLINE];
24 | rio_t rio;
25 | static pthread_once_t once = PTHREAD_ONCE_INIT;
26 |
27 | Pthread_once(&once, init_echo_cnt);
28 | Rio_readinitb(&rio, connfd);
29 | while ((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0) {
30 | P(&mutex);
31 | byte_cnt += n;
32 | printf("thread %d receive %d (%d total) bytes on fd %d\n",
33 | (int)pthread_self(), n, byte_cnt, connfd);
34 | V(&mutex);
35 | Rio_writen(connfd, buf, n);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/sample/ch12/hello.c:
--------------------------------------------------------------------------------
1 | /*
2 | * p658 -- code/conc/hello.c
3 | *
4 | * 下面的代码展示了一个简单的 Pthreads 程序。主线程创建一个对等线程,然后等待它的
5 | * 终止。对等线程输出“Hello, world\n”并且终止。当主线程检测到对等线程终止后,它
6 | * 就通过调用 exit() 终止该进程。
7 | *
8 | * unix> cc -Wall -I../../common hello.c ../../common/csapp.c -lpthread -o hello
9 | * unix> ./hello
10 | */
11 |
12 | #include "csapp.h"
13 |
14 | void *thread(void *argvp);
15 |
16 | int main()
17 | {
18 | pthread_t tid;
19 | Pthread_create(&tid, NULL, thread, NULL);
20 | Pthread_join(tid, NULL);
21 | exit(0);
22 | }
23 |
24 | void *thread(void *argvp) /* Thread routine */
25 | {
26 | printf("Hello, world!\n");
27 | return NULL;
28 | }
29 |
--------------------------------------------------------------------------------
/sample/ch12/sbuf.h:
--------------------------------------------------------------------------------
1 | /*
2 | * p671 -- code/conc/sbuf.h
3 | */
4 |
5 | #ifndef __SBUF_H__
6 | #define __SBUF_H__
7 |
8 | #include
9 |
10 | typedef struct {
11 | int *buf; /* Buffer array */
12 | int n; /* Maximum number of slots */
13 | int front; /* buf[(front+1)%n] is first item */
14 | int rear; /* buf[rear%n] is last item */
15 | sem_t mutex; /* Protects accesses to buf */
16 | sem_t slots; /* Counts available slots */
17 | sem_t items; /* Counts available items */
18 | } sbuf_t;
19 |
20 | void sbuf_init(sbuf_t *sp, int n);
21 | void sbuf_deinit(sbuf_t *sp);
22 | void sbuf_insert(sbuf_t *sp, int item);
23 | int sbuf_remove(sbuf_t *sp);
24 |
25 | #endif /* __SBUF_H__ */
26 |
--------------------------------------------------------------------------------
/sample/ch12/sharing.c:
--------------------------------------------------------------------------------
1 | /*
2 | * p662 -- code/conc/sharing.c
3 | *
4 | * 这段代码用来说明关于多线程程序中的共享变量。下面的代码由一个创建了两个对等线程
5 | * 的主线程组成。主线程传递一个唯一的 ID 给每个对等线程,每个对等线程利用这个 ID
6 | * 输出一条个性化的信息,以及调用该线程例程的总次数。
7 | *
8 | * 在 UNIX 系统下编译和运行:
9 | *
10 | * unix> make sharing # 编译时可能会有警告,可以忽略
11 | * unix> ./sharing
12 | */
13 |
14 | #include "csapp.h"
15 |
16 | #define N 2
17 |
18 | void *thread(void *vargp);
19 |
20 | char **ptr; /* Global variable */
21 |
22 | int main()
23 | {
24 | int i;
25 | pthread_t tid;
26 | char *msgs[N] = {
27 | "Hello from foo",
28 | "Hello from bar"
29 | };
30 |
31 | ptr = msgs;
32 | for (i = 0; i < N; i++)
33 | Pthread_create(&tid, NULL, thread, (void *)i);
34 | Pthread_exit(NULL);
35 | return 0;
36 | }
37 |
38 | void *thread(void *vargp)
39 | {
40 | int myid = (int)vargp;
41 | static int cnt = 0;
42 | printf("[%d]: %s (cnt=%d)\n", myid, ptr[myid], ++cnt);
43 | return NULL;
44 | }
45 |
--------------------------------------------------------------------------------