Linux应用开发基础
- 由源文件到可执行文件分为四部分
- 预编译 gcc -E main.c -O main.i
- 编译 gcc -S main.i -O main.s
- 汇编 gcc -C main.s -O main.o
- 链接 gcc main.o -O main
- Makefile
- GDB调试程序
- debug和release版本的区别
- gcc -g 编译debug版本
- 通常使用gdb调试程序
- l 显示代码
- b 行号/函数名 加断点
- info break 查看断点信息
- r 运行程序
- n 单布执行
- p 打印内容
- c 继续运行
- s 进入函数
- finish 退出函数
- q 退出程序
- bt 函数调用栈的关系
- 静态库和共享库
- libxxx.a(静态库)、libxxx.so(共享库)
- 库文件默认在/lib、/usr/lib,头文件默认放在/usr/include下
- 静态库:
- ar crv libxx.a a.o b.o
- gcc -o main main.c -L路径 -l库名
- 共享库
- gcc -shared -fPIC -o libfoo.so add.o max.o
- gcc -o main main.c -L路径 -l库名(在使用该命令时,默认优先使用共享库)
- 在运行共享库时默认再标准目录下找共享库,使用ldd命令查看库调用情况
- 主函数入口参数
- argc:参数数量
- grgv:参数内容
- 数组指针:int (*p)[] = NULL
- 指针数组:int *p[n] = {NULL}
- envp:环境变量,环境变量继承自父进程,在命令行中执行程序时,父进程就是bash命令行,可以使用export添加环境变量
- 输出缓冲区
- 在执行printf时,会将数据发送到数据缓冲区,数据缓冲区在积攒一定数据后,会将数据打印到窗口
- 使用\n换行符会将数据立刻打印输出
- 使用fflush(stdout)刷新缓冲区
- 如果不刷新缓冲区,数据不会被打印,默认在exit函数中进行刷新,若使用_exit(1)可以观察到,无数据输出
- fork复制进程
- 父进程的fork()结果不为0,子进程为0
1 |
|
- fork写时拷贝技术
- 物理内存、逻辑内存:程序内存在物理内存中空间是不连续的,在逻辑内存中不是连续的,一般采用页表进行映射,一般情况一页的大小为4K
- 页表:逻辑内存到物理内存的映射关系
- 由于两者采用页表进行映射,所以可以使不同进程的逻辑页映射到相同的物理页
- 在进行进程复制时,若对物理页完全复制,则在物理内存中会出现较多重复内容(有的页数据只读,并不修改),会浪费机器性能,所以采用写时拷贝技术
- 某页数据需要进行修改,则将该页复制到其他页上,修改逻辑页表,改变映射关系
- 逻辑地址与物理地址
- 程序中看到的地址一般为逻辑地址
- 在32位中最大内存4G
- 高位1G: 内核使用
- 低位3G: 用户使用
- 相同逻辑地址可能不是相同物理地址
- 僵死进程(defunct)
- 当子进程先于父进程结束,父进程没有获取子进程的退出码,此时子进程变成僵死进程
- 在lunix中子进程退出后,程序实体会被去除,但PCB会被保留,父进程从子进程的PCB中可以获取子进程的退出码
- 避免产生僵死进程
- 父进程调用wait()方法获取子进程的退出码,此时会阻塞
- 父进程先结束:在lunix中父进程结束后子进程如果没结束被称为孤儿进程,会被分配一个父进程(init进程),init进程会收养其他孤儿进程,在子进程结束后获取子进程退出码
- 退出码左移8位后的数据是wait返回数据
1 |
|