一般指在操作系统中用来指定操作系统运行环境的一些参数,
也就是用于存放和系统/软件环境相关信息的特殊变量
path/PATH:本质是一种环境变量,用于存放应用程序的路径信息;
当应用程序的路径存放到该变量之后,就可以直接通过该程序的名称来启动;
而不在需要路径信息
linux系统中的配置方法:
打开终端,执行一下命令:export PATH= $PATH:.
只对当前终端有效;为了使环境变量的配置对后续所有的终端有效,
则需要修改配置文件,流程如下:
vi ~/.bashrc 在文件的末尾增加一下指令:
export PATH=$PATH:.
source ~/.bashrc 使配置文件立刻生效
处理意外情况的方法:
打开主文件夹,使用ctrl+h显示所有隐藏文件,找到.bashrc文件,
使用鼠标右键,选择使用文件编辑器打开,修改对应的指令并保存即可;
编程相关的常用环境变量:
CPATH/C_INCLUDE_PATH:存放c语言文件路径
export CPATCH=$CPATH:..
CPLUS_INCLUDE_PATH:存放c++头文件的路径
LIBRARY_PATH:存放库文件所在的路径,解决编译链接时找不到库文件问题
LD_LIBRARY_PATH:存放共享库所在的路径,解决运行时找不到库文件问题
export LIBRARY_PATH=$LIBRARY_PATH:.
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
查找头文件的主要方式
#include <>
表示从系统默认的路径中查找该头文件;
当前系统中默认的路径是: /usr/include/... ...
使用命令whereis stdio.h 来查找该文件的位置
#include ""
表示优先从当前工作目录中查找,如果查找不到也会去系统默认的路径中进行查找;
配置环境变量CPATH/C_INCLUDE_PATH
export CPATH=$CPATH:头文件的路径
export CPATH=$CPATH:..
通过编译选项来指定头文件
gcc/cc xxx.c -I 头文件的路径
gcc/cc xxx.c -I ..
库文件的概念和使用
在大型项目开发中,如果每个函数都放在不同的.o文件中,
则项目管理是灾难性问题,使用库文件可以解决该问题;
一般来说,为了调用者的使用方便,
会将具体某一个功能模块中的所有.o文件打包成一个/多个库文件,编写者只需要提供库文件和头文件即可;
库文件主要分为两种:静态库文件(.a)和共享库文件(.so)
****************************************************************
****************************************************************
静态库的基本概念和基本特性
基本概念
静态库本质就是由若干个.o文件打包生成的.a文件;
链接静态库的本质就是将静态库中被调用的代码指令复制到调用模块中,体现在最终的可执行文件中;
基本特性
使用静态库的代码在运行时不需要跳转,因此执行效率高
使用静态库的代码在运行时不需要依赖于静态库文件
使用静态库生成的可执行文件可能会比较大
静态库中的代码一旦修改则必须重新链接才能生效
静态库的生成和调用步骤
生成步骤
a.编写源代码文件xxx.c,如: vi add.c
b.只编译不链接生成目标文件xxx.o,如:cc -c add.c
c.生成静态库文件
ar -r/*插入*/ lib库名.a 目标文件
ar -r libadd.a add.o
*****************************************************************
1.创建文件并运行保证程序没有bug;
比如创建 add.h,add.c,sub.h,sub.c,add_submain.c
2.编译成目标文件.o文件;比如:gcc -c add.c;gcc -c sub.c
3.打包成静态库文件;ar -r libadd_sub.a add.o sub.o
// 多个目标文件可以生成一个静态库文件
4.运行静态库文件;gcc add_submain.c libadd_sub.a(需要在后面运行) 即可正常运行
生成静态库文件之后,可以将其add.c,sub.c,add.o,sub.o文件删除
****************************************************************
****************************************************************
共享库的概念和特性
基本概念
共享库本质就是由若干个目标文件(.o)打包生成的.so文件
链接共享库的本质就是将被调用的代码指令在共享库中的相对地址嵌入到调用模块中,
体现在最终的可执行文件中;
基本特性
共享库占用空间小,即使修改了库中的代码,只要接口(相对地址)保持不变,则不需要重新链接;
使用共享库的代码在运行时需要依赖于具体的库文件,执行效率相对静态库来说略低;
目前主流的商业开发中都使用共享库方式;
共享库的生成和调用步骤
(1)生成步骤
a.编写源代码文件xxx.c,如:vi add.c
b.只编译不链接生成目标文件xxx.o,如:
cc -c -fpic/*生成位置无关码,也就是相对地址*/ add.c
c.生成共享库文件,具体指令如下:
cc -shared 目标文件 -o lib库名.so
cc -shared add.o -o libadd.so
(2)调用步骤
a.编写测试源代码文件xxx.c,如:vi main.c
b.只编译不链接生成目标文件xxx.o,如:
cc -c main.c
c.链接共享库文件,链接的方式有以下三种:
1)直接链接
cc main.o libadd.so
2)使用编译选项进行链接
cc main.o -l 库名 -L 库文件所在的路径
cc main.o -l add -L .
3)配置环境变量LIBRARY_PATH
export LIBRARY_PATH=$LIBRARY_PATH:.
cc main.o -l add
********************************************************************
1.创建文件并运行保证程序没有bug;
2.编译成目标文件.o文件;比如:gcc -c -fpic add.c gcc -c -fpic sub.c
3.打包成共享库文件;gcc -shared add.o sub.o -o libmath.so
// 运行时需要保证环境变量中包含共享文件库所在的路径;(必须设在,否则无法运行)
// 解决运行时找不到库文件的问题,配置方法如下:
4.export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
5.运行共享库文件;gcc add_submain.c libadd_sub.a(需要在后面运行) 即可正常运行
生成共享库文件之后,可以将其add.c,sub.c,add.o,sub.o文件删除
****************************************************************
****************************************************************
注意:
当使用共享库文件时,需要配置环境变量LD_LIBRARY_PATH来解决运行时找不到库文件的问题
具体配置方法如下:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
注意:
gcc编译器缺省链接共享库,可以通过-static选项强制链接静态库
使用ldd a.out 可以查看a.out所依赖的共享库
共享库的动态加载
#include <dlfcn.h>
Link with -ldl.
(1)dlopen函数
void *dlopen(const char *filename, int flag);
第一个参数:字符串形式的文件名
第二个参数:具体的操作标志
RTLD_LAZY - 表示延迟加载
RTLD_NOW - 表示立即加载
返回值:成功返回该文件对应的句柄(标识),失败返回NULL;
函数功能:
主要用于打开/加载第一个参数指定的共享库文件;
dlsym函数
void *dlsym(void *handle, const char *symbol);
第一个参数:void*的句柄信息,dlopen函数的返回值
第二个参数:字符串形式的符号名,这里指函数名
返回值:成功返回符号名对应的内存地址,失败返回NULL;
函数功能:
主要用于查找指定共享库中指定函数在内存空间的地址;
dlclose函数
int dlclose(void *handle);
函数功能:
主要用于关闭/卸载参数指定的共享库文件,参数一般传递dlopen函数的返回值;
成功返回0,失败返回非0;
dlerror函数
char *dlerror(void);
函数功能:
主要用于在调用dlopen()/dlclose()/dlsym()之后进行错误原因的获取,如果没有产生错误,则返回NULL,如果产生错误了,则返回对应的错误信息;
2.C语言中的错误处理
如:
int main(void)
{
if(...)
{
return -1; // 表示程序出错结束
}
return 0; // 表示程序正常结束
}
2.1 C语言中的错误表现形式(错了吗?)
一般来说,C语言中的函数都是通过返回值来表达是否出错的,而具体的表现规则如下:
(1)对于返回值类型为int的函数来说,如果函数的计算结果不可能是负数时,一般使用返回-1表示出错,返回其他数据表示正常结束;
(2)对于返回值类型为int的函数来说,如果函数的计算结果可能是负数时,一般使用指针作为函数的形参用于将函数的计算结果带出去,而函数的返回值专门用于表示是否出错,一般使用返回-1表示出错,返回0表示正常结束;
(3)对于返回值类型为指针类型的函数来说,一般使用返回NULL来表示调用失败/出错;
(4)对于不考虑是否失败的函数来说,返回值类型直接使用void即可;
2.2 错误编号(为什么错了?)
errno本质上就是一个int类型的全局变量,当系统/库函数调用失败时,会自动设置errno的数值来表达错误的原因;
#include <errno.h> 包含了对errno变量的外部声明以及各种错误的编号定义等;
/etc/passwd - 用于存放当前系统的账户管理信息等;
/etc/shadow - 用于存放当前系统的账户密码信息等