分文件编程:
- 好处:分模块编程思想,功能和责任划分清楚便与调试,main函数简洁,代码易于阅读。
- 编程时头文件有的是使用<>这个符号括起来的,有的是" "使用的是双引号,使用尖括号括起来默认从/user/include/下面去找头文件或者是/user/local/include/下面去找,而使用双引号是默认从当前文件路径去找。
一个小栗子(两个数相加):
- mainadd.c文件
#include<stdio.h>
#include"addfunc.h"
int main()
{int a,b,sum;printf("input first number:\n");scanf("%d",&a);printf("input second number:\n");scanf("%d",&b);sum=add(a,b);printf("sum is %d\n",sum);return 0;
}
- addfunc.c文件,这个文件里面主要是函数体,函数的内部代码在这个文件里面写。
int add(int number1,int number2)
{int sum;sum=number1+number2;return sum;
}
- addfunc.h文件代码,这个文件主要是函数的声明,addfunc.h这个文件在main函数头文件里面要被包含。
int add(int number1,int number2);
- 然后执行指令:
gcc mainadd.c addfunc.c -o add
进行编译
首先了解一下gcc编译器的工作流程:
Linux静态库、动态库(共享库)详解:
- 在项目开发过程中,经常出现优秀代码重用现象,又或者提供给第三方功能模块却又不想让其看到源代码,这些时候,通常的做法是将代码封装成库或者框架,生成的静态库要和头文件同时发布。
- 静态库特点: 静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。静态库优点: 寻址方便,速度快;库在链接时被打包到可执行文件中,直接发布可执行程序即可以使用;发布程序无需提供静态库,因为已在app中,移植方便静态库缺点: 静态库的代码被加载到可执行程序中,因此体积过大;如果静态库的函数发生改变,必须重新编译可执行程序;链接时完整的拷贝至可执行文件中,被多次使用就有多份冗余的拷贝;更新、部署、发布、比较麻烦。
- 动态库特点: 动态库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小,因此在程序运行时还需要动态库存在。动态库优点: 节省内存;易于更新,不用重新编译可执行程序,运行时自动加载;链接时不复制,程序运行时由系统动态加载到内存,供程序使用,系统只加载一次,多个程序可以共用,节省内存。动态库缺点: 延时绑定,速度略慢;发布程序需要提供依赖的动态库。注意: 动态函数库和共享函数库是一个东西(在Linux上叫共享对象库,文件后缀是.so在windows上叫做动态函数加载库,文件后缀是.dll)。
- Linux中命名系统中共享库的规则:
静态库的制作与使用:
- 命名规则: 静态库文件名的命名方式是“libxxx.a”,库名前加”lib”,后缀用”.a”,“xxx”为静态库名。
- 制作过程: 原材料:源代码.c 或者 .cpp。
- 第一步: 将.c文件生成.o,
gcc 源代码.c -c
这里是要将功能函数的.c文件生成.o文件。就用上面的那个例子:将addfunc.c生成.o文件。
gcc addfunc.c -c得到:addfunc.o
- 第二步; 将.o 打包ar rcs 静态库的名字 原材料,原材料就是上面生成的.o文件,静态库名字尽量符合静态库的命名规则。
ar rcs libaddfunc.a addfunc.o得到:libaddfunc.a
- 静态库的使用: 当静态库制作完成后,此时不再需要addfunc.c这个文件了,将它移除也不会造成任何影响。但是需要addfunc.h这个文件,因为main函数里面有包含这个头文件。当别人需要你的代码时只需将.h和.a文件提供给他们即可。静态库使用格式:
gcc mainadd.c -laddfunc -L ./
若直接-l 编译会报错,因为-l 会优先从/urs/lib 或 /urs/local/lib 中去找,但我们想让它优先从当前路径去找,就要用到-L ./
。使用静态库时一般去掉lib和后面的.a直接-l+静态库的名字即可。
gcc mainadd.c -laddfunc -L ./ -o add
得到:add这个可执行文件
动态库的生成和使用:
- 命名规则: 动态库的命名方式与静态库类似,前缀相同,为“lib”,后缀变为“.so”。所以为“libaddfunc.so”
- 制作指令:
gcc -shared -fpic addfunc.c -o libxxx.so
其中-shared
是指定生成动态库,-fpic
的作用是:作用于编译阶段,在生成目标文件时就得使用该选项,以生成位置无关的代码。
gcc -shared -fpic addfunc.c -o libaddfunc.so
得到: libaddfunc.so
- 动态库的使用: 动态库的使用和静态库的使用方法是一样的,
gcc mainadd.c -laddfunc -L ./ -o add
其中mainadd.c 是主函数,addfunc是动态库的名字。
gcc mainadd.c -laddfunc -L ./ -o add
得到:add这个可执行文件
但是./add会报错,而静态库生成的可执行文件却不会报错,
原因是动态库在生成可执行程序时没有把动态库包含进去,
是在程序运行过程中临时由目标调用动态库,静态库则是已经编译到,目标程序中了。
- 这时我们就需要将自己制作的动态库拷贝到/user/lib/下面,因为他默认的会从/user/lib/下面去找动态库。
sudo cp libaddfunc.so /usr/lib/
//这时候在执行就不会报错了。
- 那么如何在程序执行的时候从当前路径下去找动态库呢?通过环境变量
LD_LIBRARY_PATH
指定动态库搜索路径,export LD_LIBRARY_PATH="/home/pi/linuxfile/file1"
但是这样的环境变量是临时的,当退出后还要重新设置环境变量。所以我们可以使用脚本,将export LD_LIBRARY_PATH="/home/pi/linuxfile/file1"
放到脚本里面并且添加./add这个可执行文件的名称
,然后chmod +x start.sh
给这个脚本添加可执行的权限。
- 还可以使用
du + 库的名称计算文件或者可执行程序的大小
例如:du add
或者du libaddfunc.so
- 除了上面哪种方法以外,还在网上看到以下两种方法:第一种方法:gcc + 源文件 + -L 动态库路径 + -l动态库名 + -I头文件目录 + -o 可执行文件名
gcc main.c -L lib -l MyTest -I include -o app
然后./app
会报错:(执行失败,找不到链接库,没有给动态链接器(ld-linux.so.2)指定好动态库 libmytest.so 的路径)第二种方法:gcc + 源文件 + -I头文件 + libxxx.so + -o 可执行文件名
gcc main.c -l include lib/libMyTest.so -o app
(执行成功,已经指明了动态库的路径) - 如何解决第一种方法中找不到链接库的问题?
- 使用命令
ldd app
可以查看当前的链接库情况。第一种方法:
export LD_LIBRARY_PATH=自定义动态库的路径(只能起到临时作用,关闭终端后失效)LD_LIBRARY_PATH : 指定查找共享库(动态链接库)时除了默认路径之外的其他路径,该路径在默认路径之前查找。第二种方法:将上述命令写入home目录下的.bashrc文件中,保存后重启终端生效(永久)第三种方法:直接将动态库拷贝到user/lib的系统目录下(强烈不推荐!!)第四种方法:将libmytest.so所在绝对路径追加入到/etc/ld.so.conf文件,使用sudo ldconfig -v 更新
进入/etc/ld.so.conf.d这个文件路径下,新建一个自己的.conf,我这里是mylib.c将动态库的绝对路径加进去然后使用sudo ldconfig -v
更新,就可以运行可执行文件了。
Linux环境变量详解:
- 环境变量的含义: 环境变量一般是指操作系统中指定操作系统运行环境的一些参数。它相当于一个指针,想要查看变量的值,需要加上“$”。
- 环境变量的分类: 按作用的范围: 分在Linux中的变量,可以分为环境变量和本地变量:①环境变量:相当于全局变量,存在于所有的Shell中,具有继承性;②本地变量:相当于局部变量只存在当前Shell中,本地变量包含环境变量,非环境变量不具有继承性。 按生存周期分: ①永久:需要修改配置文件,变量永久生效;②暂时:使用export定义,关闭Shell后失效。
- 环境变量的组织方式: 每个程序都有一张环境表,环境表是一个指针数组,每个指针指向一个以‘\0’结尾的环境字符串。Main函数的第三个参数就是环境表地址。
常见的环境变量: - PATH: 变量指定命令的搜索路径。
使用指令echo $PATH
:可以查看在当前目录下PATH的值。它表示在当前目录下执行的每一条指令的搜索路径,每个目录以冒号隔开。当执行一条指令时,系统就会从系统文件中去寻找,找到了就执行;否则不执行。
-
HOME: 该变量指定用户的主工作目录,即用户登录到Linux系统时,默认的目录。 这个环境变量一个变量,它的值随着用户的不同而不同。
普通用户下的主工作目录
sudo -s进入超级用户权限
, 超级用户下的主工作目录 -
LOGNAME: 该变量指定显示用户的登录名。
-
HOSTNAME: 该变量指定主机名
-
SHELL: 该变量指定用户当前使用的解析器。
修改和显示环境变量的命令 :
-
echo: 该命令用于显示某个环境变量的值。
-
env : 该命令指定显示所有的环境变量和值。
-
set: 显示系统中已经存在的shell变量,以及设置shell变量的新变量值。使用set更改shell特性时,符号"+“和”-"的作用分别是打开和关闭指定的模式。set命令不能够定义新的shell变量。如果要定义新的变量,可以使用declare命令以变量名=值的格式进行定义即可。
-
使用
declare
命令定义一个新的环境变量"mylove
",并且将其值设置为"Visual C++",输入如下命令:declare mylove='Visual C++' #定义新环境变量
再使用set命令将新定义的变量输出为环境变量,输入如下命令:set -a mylove #设置为环境变量
执行该命令后,将会新添加对应的环境变量。用户可以使用env命令和grep命令分别显示和搜索环境变量"mylove",输入命令如下:env | grep mylove #显示环境变量值
-
export : 该命令指定设置一个新的环境变量。注意:环境变量一般用英文字母大写加下划线表示。
-
unset : 该命令指定清除环境变量。
- readonly : 该命令用于设置只读环境变量,将环境变量MY_ENV设置为只读模式后,就不能在对它进行修改了,直到用户退出登录后才失效。
5、存放环境变量的文件
几个文件的作用:
- /etc/profile 该文件的作用是当用户登录时获取系统的环境变量,只获取一次。
- /etc/bashrc 当执行完/etc/profile文件后,用户想打开bash Shell就会读取该文件。如果想每次打开bash Shell后都执行某些操作,可以在该文件中设置。
- ~/.bash_profile 每个用户都可使用该文件输入专用于自己使用的shell信息。当用户登录时,该文件仅仅执行一次,默认情况下,它设置一些环境变量,执行用户的.bashrc文件。单个用户此文件的修改只会影响到他以后的每一次登陆系统。因此,可以在这里设置单个用户的特殊的环境变量或者特殊的操作,那么它在每次登陆的时候都会去获取这些新的环境变量或者做某些特殊的操作,但是仅仅在登陆时。
- ~/.bashrc 该文件包含专用于单个人的bash shell的bash信息,当登录时以及每次打开一个新的shell时,该该文件被读取。单个用户此文件的修改会影响到他以后的每一次登陆系统和每一次新开一个bash。因此,可以在这里设置单个用户的特殊的环境变量或者特殊的操作,那么每次它新登陆系统或者新开一个bash,都会去获取相应的特殊的环境变量和特殊操作。
- ~/.bash_logout 当每次退出系统(退出bash shell)时,执行该文件。
环境变量部分参考这篇博文