-
Unix操作系统
用C写的操作系统
系统特点:多用户、多任务,支持多种处理器架构,具有高安全性、高可靠性、高稳定性
既可以构建大型关键业务系统的商用服务器,也可以构建面向移动终端的、手持设备的系统
三大衍生版本
System V:银行、电信公司 服务器系统
Brekley:MacOS iOS带界面
Hybrid:Minix、Linux -
Linux操作系统
类Unix系统,免费开源,它是指系统的内核,凡是使用这种内核的操作系统都叫做Linux系统(发行版)。
严格意义上讲Linux指的是内核,隶属于GNU工程。
一般用在:手机、平板电脑、路由器、视频游戏控制台、PC、大型计算机、超级计算机
标志是一只企鹅(tux)
Minix操作系统是Unix系统的简化版,是开源的、免费的,Linux之父就是参照这款系统,才写出第一个版本的Linux内核代码GNU工程,由自由软件基金会所创立的一个开源的组织,基本原则就是共享。主旨是发展出一个有别于商业的UNIX的免费且完整的UNIX系统目前Linux由GNU维护,所以Linux也会叫 GNU Linux
GPL通用公共许可证:允许对某些成果及派生成果重用修改复制,对所有人都是自由的。
POSIX:可移植操作系统接口(Portable Operating System Interface of UNIX,缩写为 POSIX)POSIX标准定义了操作系统应该为应用程序提供的接口标准(名字、参数、返回值),
是IEEE为要在各种UNIX操作系统上运行的软件而定义的一系列API标准的总称,其正式称呼为IEEE 1003,而国际标准名称为ISO/IEC 9945。
//保障了应用程序源码级的可移植性,linux完全遵循。版本管理:
早期:0.01\0.02、…、0.09\1.0
就计划:A.B.C
A主板本号
B次版本号
C补丁序号
新计划:A.B.C.D.E
D构建次数
E描述信息
- linux特点
- 多用户、多任务
- 遵循GNU/GPL具有开放型
- 设备独立性
- 丰富的网络功能
- 可靠的系统安全
- 良好的可移植性
- 发行版
- Debian
- Ubuntu
- Fedora
- Redhat
- CentOS
-
GNU编译器
- 支持众多编程语言和平台
- 构建过程(c代码怎么变成可执行文件)
- 如何查看版本//gcc -v
- 文件后缀
- .h 头文件 .gch 头文件编译结果//一般删除
- .c 源文件 .i 预处理文件
- .s 汇编文件 .o 目标文件
- .a 静态库文件 .so 共享库文件
- 参数
- -E 预处理
- -S 汇编
- -c 编译(生成目标文件)
- -o 指定编译结果的名字
- -Wall 产生多的警告
- -Werror 警告当错误
- -x 指定编译语言
- -g 生成调试信息
- -On 编译优化的级别 优化的等级// O1 O2 O3
- -D 编译时定义宏
- -l 链接时添加库
- -I 指定头文件的查找路径,配置环境变量
打开 vim ~/.bashrc
在文件末尾加上一行export C_INCLUDE_PATH=$C_INCLUDE_PATH:NEW_PATH//=$...:
重新加载配置文件source ~/.bashrc
注意:如果要删除环境变量需要在~/.bashrc文件删除后,退出终端重新打开
考题:#include <> / #include ""
区别
头文件中可以编写哪些东西
头文件的作用
主要用于保存程序的声明,而定义文件用于保存程序的实现,定义结构、联合、枚举、宏,类型重定义//函数虽然可以隐式声明,但并不一定准确,而且错的几率很高,可能造成严重错误r
头文件的主要作用在于多个代码文件全局变量(函数)的重用、防止定义的冲突,对各个被调用函数给出一个描述,其本身不需要包含程序的逻辑实现代码,它只起描述性作用,用户程序只需要按
照头文件中的接口声明来调用相关函数或变量,链接器会从库中寻找相应的实际定义代码。
编译时头文件找不到
预处理指令
#include
#define
#undef 删除宏
#if
#ifndef
#elif
#define zhu(a) #a /# 把标识付转化成字符串/
#define zhu(a) a##1 /## 合并标识符/
#error //在编译期间产生错误
#warning //在编译期间产生警告
#pragma
#pragma GCC dependency //监控文件,防止所以依赖的文件修改后而不知道
#pragma GCC poison //用于禁用某些标识符
#pragma pack(n) //设置结构、联合的补齐和对齐字节数 n必须是2的较小次方必须小于默认值
#line //指定当前行的行号 -
库
库就是目标文件的集合,我们把不需要升级和更新维护的代码打包合并在一起,方便使用(分久必合合久必分),也可以对源代码进行保密 -
静态库
二进制的一种集合 它在使用时,是把被调用的代码复制到调用模块中,之后在执行可执行程序时,静态库就不要了
执行速度快,占用空间大,不能轻易修改库中的内容(库中内容变化时,需要重新编译)//不方便更新
静态库的扩展名.a1、创建静态库
编译源程序:vi .c/.h
编译代码: gcc -c xxx.c -> xxx.o
打包生成静态库: ar -r libxxx.a x1.o x2.o …
-r 把目标文件添加到静态库中,已经存在则更新
-q 将目标文件添加到静态库末尾
-d 从静态库中删除目标文件
-t 显示静态库有哪些文件
-x 把静态库差分成目标文件
2、调用静态库
直接调用:调用者和库要在同一路径下 gcc main.c libxxx.a
设置环境变量:设置方法与C_INCLUDE_PATH类似export LIBRARY_PATH=$LIBRARY_PATH:
source ~/.bashrc
gcc main.c -lmath
通过参数:-L路径
gcc main.c -L路径 -lmath
3、运行静态库
编译时已经把被调函数的二进制文件复制到可执行文件了,所以之后用不到静态库 -
共享库
在调用模块中嵌入调用代码在库的相应位置的地址,之后在执行可执行程序时,共享库一起加载进内存,先跳到共享库执行相应代码,之后跳回
占用空间小,方便更新(程序不需要重新编译),相对于静态库 它的执行效率略低
共享库的扩展名.so1、创建动态库:
vi .c/.h
编译出位置无关目标文件:
gcc -c -fpic xxx.c -> xxx.o
链接生成共享库
gcc -shared xxx.o … -o libxxx.so
2、调用动态库
直接调用
设置环境变量3、运行动态库
在使用共享库时,调用者只是记录了代码在库的位置,所以要一起加载
操作系统会根据LD_LIBRARY_PATH -
动态加载共享库
#include <dlfcn.h>
1、加载共享库
void *dlopen(const char filename(共享库的库名,或路径),int flag)
flag
RTLD_LAZY:使用时加载
RTLD_NOW:立即加载
返回值:共享库的句柄(打开文件的权限//类似文件指针)
2、获取标识符地址并使用
void dlsym(void handle, const char symbol)
handle:共享库的句柄
symbol:文件标识符的名字
返回值:标识符在共享库中的地址(地址,可以解引用或跳转)
3、卸载共享库
void *dlclose(void *handle)
返回值:
success 0
false -14、获取错误信息
void *dlerror(void)
返回值:在使用共享库过程中的错误以字符串返回 -
辅助工具
nm:查看目标文件,可执行文件、静态库、共享库中的符号标志
ldd:可以查看可执行文件所依赖的共享库有哪些
strip:去除掉目标文件、可执行文件、静态库、共享库中的符号列表、调试信息
objdump:可以将二进制的可执行文件转换成汇编语言