Unix/Linux环境C语言,借助学习操作系统的接口的方法来学习、理解操作系统的运行机制以及一些网络协议
C/C++ 、数据结构和算法 与平台无关,重点是算法逻辑
Unix/Linux/Android/iOS 平台相关,系统接口
嵌入式/驱动/移植 硬件相关,硬件接口
丹尼斯·里奇、肯·汤普逊于1971左右在美国贝尔实验室,使用C语言开发了这款操作系统
系统的特点是多用户、多任务,支持多种处理器架构,高安全性,高可靠性、高稳定性
既可以构建大型关键业务系统的商用服务器,也可以构建面向移动终端的、手持设备等相关的嵌入式应用
三大衍生版本
System V:银行、电信在使用的服务器系统
Berkley :MacOS iOS带界面的
Hybrid:Minix、Linux
类Unix系统,免费开源,它指的是系统的内核,凡是使用这种内核的操作系统都叫作Linux系统(发行版),严格意义上讲Linux指的是内核,隶属于GNU工程
手机、平板电脑、路由器、视频游戏控制台、PC、大型计算机、超级计算机
标志是一只企鹅,因为企鹅是南极的标志性动物,根据国际公约南极为全人类共同所有,所以Linux使用企鹅作为标志,也表明:开源的Linux为全人类共同所有,任何公司或个人无权将其私有
Minix操作系统是一个微型的类Unix系统、免费开源,而Linux之父就是在参照这款操作系统,才写出了第一个版本的Linux内核代码
GNU工程是自由软件基金会所创立的一个开源组织,基本原则就是共享,主旨是发展出一个有别于商业Unix的免费且完整的类Unix系统--GNU Not UNIX.目前Linux内核由它进行维护,所以Linux也叫GNU Linux
GPL通用公共许可证:允许对某些成果及派生成果重用、修改、复制,对所有人都是自由的,但不能声明做了原始工作,或声明由他人所做
POSIX标准:Portable Operating System Interface of Unix,缩写为POSIX,统一的系统编程接口规范,它规定了操作系统以接口形式提供的功能的名字、参数、返回值,它保障了应用程序源码级的可移植性,而Linux完全遵循了这个标准
版本管理:
早期版本:0.01、0.02、。。。、0.09、1.0
旧计划:A 主版本号 cat /proc/version B 次版本号 C 补丁序号
新计划:A.B.C.D.E D 构建次数 E 描述信息
特点:
多用户、多任务;遵循GNU/GPL具有开放性;设备独立性;丰富的网络功能;可靠的系统安全;良好的可移植性;
发行版:
Ubuntu/Fedora/Debian/Redhat/CentOS
1.支持众多编程语言、平台
2.构建过程(C代码是如何变成可执行文件的)
预处理:把程序员所编译的C代码翻译成标准的C代码
编译:把预处理后的C代码翻译成汇编代码
汇编:把汇编代码翻译成二进制指令
链接:把若干个目标文件合并成一个可执行文件
3.查看版本
gcc -v
4.文件后缀
.h 头文件
.gch 头文件的编译结果,一般不要保留
.c 源文件
.i 预处理文件
.s 汇编文件
.o 目标文件
.a 静态库文件
.so 共享库文件
5.参数
-E 预处理
-S 产生汇编文件
-c 只编译不链接(只生成目标文件)
-o 指定编译结果的名字 输出文件
-Wall 产生尽可能多的警告
-Werror 把警告当作错误处理
-x 指定编译的语言
-g 生成调试信息
-On: -O1 -O2 。。 优化等级
-D 编译时定义宏
-l 小写l 链接里加库
-I 大写i 指定头文件的查找路径,配置环境变量
1.打开 vim ~/.bashrc
2.在文件末尾,添加一行,export C_INCLUDE_PATH=$C_INCLUDE_PATH:NEW_PATH 绝对路径
3.重新加载配置文件 source ~/.bashrc
注意:如果要删除环境变量需要在~/.bashrc文件中删除环境变量后,退出终端重新打开(没有立即有效)
6.预处理指令
#include 文件包含,区分 “ ” 和 <>
#define 定义宏常量和宏函数
# 把标识符转换成字符串
## 合并标识符
#undef 删除宏
#line 指定当前行的行号
#if
#ifndef
#ifdef
#elif
#endif
#error 在编译期间产生错误
#warning 在编译期间产生警告
#pragma
#pragma GCC dependency +"文件名" 放在dome3.c 的main前 文件名的文件修改时间要早于dome3.c 用于监控文件,防止所依赖的文件,修改后而不知道
#pragma GCC poison(毒) + goto 禁止使用goto 用于禁用某些标识符,变量
#pragma pack(n) 设置结构、联合的补齐和对齐的字节数 对齐边界必须是2的较小次方 不能为3
n 的值必须比默认值的要小 <4
库就是目标文件的集合,我们把不需要升级更新维护的代码打包合并在一起方便使用,也可以对源代码进行保密
静态库:在使用时是把被调用的代码复制到调用模块中,之后再执行程序时,静态库就不需要了
静态库的执行速度快,但占用空间大,当库中的内容发生变化时,需要重新编译出新的程序,因此不能轻易修改库中的内容
共享库:只是在调用模块中嵌入调用代码的在库的相对位置的地址,当执行程序时,共享库会和程序一起加载到内存中,当执行到调用库中的代码的指令时跳转到共享中执行,执行完毕后在跳转回来
占用空间小,方便更新(共享库发生变化后,程序不需要再次编译),相对于静态库执行效率略低
静态库的扩展名为 .a ,共享库(动态库)的扩展名为 .so
1.创建静态库
编写源代码:vi .c/.h
编译源代码:gcc -c xxx.c ->xxx.o
打包生成静态库:ar -r libxxx.a x1.0 x2.o ... (*.o代替所有) 即: ar -r library.a *.o
ar命令的一些参数:
-r 把目标文件添加到静态库中,已经存在的更新
-q 将目标文件追加到静态库的末尾 ar -q libmath.a add.o
-d 删除目标文件 ar -d libmath.a add.o
-t 显示静态库中有哪些目标文件 ar -t libmath.a
-x 把静态库拆分成目标文件 ar -x libmath.a
2.调用静态库
第一种方法: 直接调用:调用者要和库在同一路径下
gcc main.c libxxx.a
第二种方法:设置环境:设置方法与C_INCLUDE_PATH类似 可以不在同一路径下
1.打开 vim ~/.bashrc
2.在文件末尾,添加一行,export LIBRARY_PATH=$LIBRARY_PATH:库文件的路径 (绝对路径)
3.重新加载配置文件 source ~/.bashrc
4.编译时要指定库名 gcc main.c -I./math(大写i)
第三种方法加载库:设置编译参数:-L库路径
gcc main.c -L库路径
3.运行
./a.out
在编译时已经把被调函数的二进制复制到可执行文件中了,在执行时不再需要静态库文件
1.创建共享库
编写源代码:vi .c/.h
编译出位置无关目标文件:gcc -c -fpic xxx.c ->xxx.o 记录函数在共享库的第几个字节,更方便加入到可执行文件中
链接生成共享库:gcc -shared x1.0 x2.o ... (*.o代替所有) 即: gcc -shared *.o -o libxxx.so
2.调用共享库
第一种方法: 直接调用:调用者要和库在同一路径下
gcc main.c libxxx.so
第二种方法:设置环境:设置方法与C_INCLUDE_PATH类似
1.打开 vim ~/.bashrc
2.在文件末尾,添加一行,export LIBRARY_PATH=$LIBRARY_PATH:库文件的路径 (绝对路径)
3.重新加载配置文件 source ~/.bashrc
4.编译时要指定库名 gcc main.c -I./math
第三种方法加载库:设置编译参数:-L库路径
gcc main.c -L库路径
3.运行
在使用共享库时,调用者只是记录了被调用代码在库的位置,因此在执行时需要共享库同时被加载
#include
1.加载共享库
void *dlopen(const char *filename, int flag);
filename : 共享库的库名,或路径
flag:
RTLD_LAZY:使用时才加载
RTLD_NOW:立即加载
返回值:共享库的句柄(类似文件指针)
2.获取标识符在共享库中的地址并使用
void *dlsym(void *handle, const char *symbol);
handle:共享库的句柄
symbol:标识符的名字
返回值:标识符在共享库中的位置(地址,可以解引用,或跳转过去)
3.卸载共享库
int dlclose(void *handle);
handle:共享库的句柄
返回值:成功返回0 失败返回-1
4.获取错误信息
char *dlerror(void);
返回值:会把在使用共享库的过程中出现的错误,以字符串的形式返回
优先调用动态共享库,-static 可以先调用静态库
nm:查看目标文件、可执行文件、静态库、共享库中的符号列表 nm a.out
ldd:查看可执行程序所依赖的共享库有哪些
strip:减肥,去除掉目标文件、可执行文件、静态库和共享库中的符号列表、调式信息
查看文件的大小: ls -l 去除:strip a.out
objdump : 显示二进制模块的反汇编信息 objdump -S a.out