第六章不看,直接到第七章
所谓的启动例程用C写起来一般是这样,但一般情况这个会是汇编来写
exit(main(argc, argv))
exit函数
_exit和_Exit立即进入kernel,exit则需要做完必要的清理工作,先run注册过的终止处理程序,然后清理没有关闭的流。
exit _Exit是ISO C标准,_exit则是Posix,所以头文件不一样
前面是stdlib.h 后面是unistd.h
关于malloc,calloc,realloc
malloc分配的空间初始值不确定;calloc会帮忙清零;realloc可以动态分配合适的大小空间,如果不够会有copy原始数据的动作,所以对realloc之前的memory记录指针不是好方法,因为realloc完就可能失效。
这三个都是去call sbrk来扩大缩小heap
但一般只是扩大,在free的时候 malloc 会把扩大的 memory cache起来(virual memory)
setjmp, longjmp
跳转函数,支持跨越函数帧的跳转,goto是函数内跳转
注意: longjmp到setjmp的点后,一般情况 全局/局部/局部静态变量都没办法恢复到setjmp时的值;register/volatile变量在编译后(cc -O)会放到寄存器中,这些都能实现回滚。这也就说明setjmp的时候,jmp_buf并没有保存这些值。
7.1 如果不调用return 和 exit 函数返回值用了printf的返回值,Orz...我没想清楚怎么做的。
7.2 取决于printf面对的设备类型,行缓冲的话,碰到换行就会被输出,如果是全缓冲,那么则要么需要call fflush,要么等stream被close。
7.3 不用参数传递,不用全局变量,Orz...要传递argc, argv -->NO
7.4 通常null就是0,一般指针为 null 的时候意味着空指针引用,一般0都不会去放数据,RO的起始位置在一个更高的地址,0会是无效的,用来指引程序出错。
7.5
typedef void func(void);
int atexit(func* fp);
或者
typedef void (*func)(void);
int atexit(func fp);
我喜欢下面那种,因为函数本身就是个pointer。
7.6 calloc会将分配的空间清零,ISO C不保证0值和空指针相等
7.7 size输出的是静态的RO,RW,ZI,像Heap,Stack是runtime才有的。
7.8 理论上不带debug信息的.out文件应该大小都是等于RO+RW+ZI的。
7.9 这就是.a和.so的区别了,link的时候静态库会被直接copy过来,所以会变大很多。
7.10 变量作用域的故事。