Linux C++服务器项目——系统编程2(静态库、动态库、文件IO)

牛客 C++高并发服务器开发
参考笔记

1 静态库和动态库

1.1 什么是库

库文件是计算机上的一类文件,可以简单的把库文件看成一种代码仓库,它提供给使用者一些可以直接拿来用的变量、函数或类。

库是特殊的一种程序,编写库的程序和编写一般的程序区别不大,只是库不能单独运行。

库文件有两种,静态库和动态库(共享库),区别是:静态库在程序的链接阶段被复制到了程序中;动态库在链接阶段没有被复制到程序中,而是程序在运行时由系统动态加载到内存中供程序调用。

库的好处:
1.代码保密;
⒉方便部署和分发;

1.2 静态库

1 命名规则

Linux : libxxx.a
1ib :前缀(固定)
×xX :库的名字,自己起
.a :后缀(固定)
windows : 1ibxxx.1ib

2 静态库的制作步骤

  1. gcc获得.o文件
  2. 将.o文件打包,使用ar 工具(archive)
ar rcs libxxx.a xxx.o xxx.o

r-将文件插入备存文件中
c-建立备存文件
s-索引

3 制作静态库

库文件如下
在这里插入图片描述

tree,查看当前目录下,文件的目录结构

sudo apt install tree

下面是,已经建好的库的结构
在这里插入图片描述
在这里插入图片描述

准备工作:
在lesson03文件夹下,新建04_calc,
在04_calc下新建calc文件夹,
在calc下依次添加add.c, sub.c, mult.c, main.c, head.h,直接从上面的02_makefile文件下拷贝过来就行;
如下:
在这里插入图片描述

制作静态库过程:
ls
1. gcc获得.o文件

gcc add.c sub.c mult.c div.c -c  #-c 汇编,生成目标文件.o

在这里插入图片描述
2. 将.o文件打包,使用ar 工具(archive)

ar rcs libxxx.a xxx.o xxx.o  
#xxx.o xxx.o是列举目标文件,这样写太麻烦了,简写尾为 *.o 
#libxxx.a库名,lib固定格式,后面xxx是库名,需自定义,,我们通常说的库名就是这个 

r-将文件插入备存文件中
c-建立备存文件
s-索引

ar rcs libcalc.a *.o //生成静态库

静态库成功
在这里插入图片描述
在04_lib下创建library文件下;
library下创建include、lib、src文件夹
在这里插入图片描述
此时文件结构
在这里插入图片描述

将calc下面的库libcalc.a,拷贝到library的lib下;
将calc/head.h,拷贝到,library/lib/;
将calc/main.c,拷贝到,library/src/;

cp calc/libcalc.a library/lib/
cp calc/head.h library/include/
cp calc/main.c library/src/

在这里插入图片描述

gcc main.c -o app

编译生成可执行文件aap

在这里插入图片描述

找不到head.h,,因为在库目录library下,head.h和main.c不在同意文件夹下;
而终端当前目录是在libray/src下,所以要指定head.h的路径

-I directory 指定include包含文件的搜索目录

. ./上一级目录

gcc main.c -o app -I ../include/

在这里插入图片描述
此时,找到head.h文件;
但是,对于main中的 add、sub、mult、div函数未找到定义;

-l 在编译的时,指定使用的库
这里指定 calc库,即 ,-l calc

gcc main.c -o app -I ../include/ -l calc

在这里插入图片描述制定了库名,,但找不到这个库

还要指定库的路径

-L 指定编译时,搜索库的路径

-L …/lib/

gcc main.c -o app -I ../include/ -l calc -L ../lib/

在这里插入图片描述
在这里插入图片描述

1.3 动态库

命名规则:

Linux : libxxx.So
 lib:前缀(固定)
 xxx∶库的名字,自己起
 .so∶后缀(固定)
 在Linux下是一个可执行文件
Windows : libxxx.dll

动态库的制作:
1.gcc得到.o文件,得到和位置无关的代码

gcc -c -fpic/-fPIC a.c b.c
#-fpic/-fPIC  大小写都可以,任意用一个

2.gcc得到动态库

gcc -shared a.o b.o -o libcalc.so

1 制作动态库

先删除所有.o 文件 rm *.o

在这里插入图片描述

1.gcc得到.o文件,得到和位置无关的代码

gcc -c -fpic *.c  #汇编所有.c文件,-fpic并生成和位置无关的代码

在这里插入图片描述
2.gcc得到动态库

gcc -shared *.o -o libcaloc.so

在这里插入图片描述
删掉,library下之前静态库生成的文件

之后:

cp ../calc/head.h ./include/
cp ../calc/main.c ./src/
cp ../calc/libcalc.so ./lib/

在这里插入图片描述

在这里插入图片描述

编译main.c生成可执行文件 app

还是和静态库一样要指定 .h文件路径,库名,库路径

gcc main.c -o app -I ../include/ -l calc -L ../lib/

app生成成功;
但是执行./app出错
在这里插入图片描述
这由,动态库和静态库区别,导致的;
下面从二者工原理来解决;

1.4 静态库和动态库工作原理

静态库:GCC进行链接时,会把静态库中代码打包到可执行程序中;
动态库:GCC进行链接时,动态库的代码不会被打包到可执行程序中;
,动态库在执行可执行文件时,会把代码单独加载到内存里,用完释放;好处,别的程序如果想用动态程序也可以直接调用;

·程序启动之后,动态库会被动态加载到内存中,通过Idd (list dynamic dependencies)命令检查动态库依赖关系

ldd app 

在这里插入图片描述

如何定位共享库文件呢?
当系统加载可执行代码时候,能够知道其所依赖的库的名字,但是还需要知道绝对路径。此时就需要系统的动态载入器来获取该绝对路径。对于elf格式的可执行程序,是由ld-linux.so来完成的,它先后搜索elf文件的DT_RPATH段—一>环境变量LD_LIBRARY_PATH -->/etc/ld.so.cache文件列表―—>/libl,lusr/lib目录找到库文件后将其载入内存。

右键:复制会话,复制一个新的远程窗口
在这里插入图片描述
在 .bashrc文件中添加库路径
cd退回到家目录,用vim打开 .bashrc

vim .bashrc

在最下面加入,路径

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/luck/Linux/lesson03/04_lib/library/lib

a启动编辑,esc退出编辑模式,:wq保存并退出,:q直接退出,:!q强制退出
在这里插入图片描述
添加后,刷新

. .bashrc 同 source .bashrc,第一个点,就等同source

再次进入src就可以执行 ./app了

cd Linux/lesson03/04_lib/library/src


上面.bashrc是用户级文件;
也可以在系统文件里面添加路径;
不过这个文件是只读文件,在文尾添加路径后,无法保存,如果想要保存,需要修改文档权限,很麻烦,就不再试了。
在这里插入图片描述

1.5 区别

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

2 文件IO

2.1 标准C IO函数

在这里插入图片描述
读写,是站在内存(程序)的角度;

文件输入到内存,读,input;
内存输出到文件,写, output;

比如,我在记事本中写一行文;
没保存时,数据在内存上,按下保存后,数据写入文件(磁盘)。
在这里插入图片描述
当我们打开记事本,显示里面的内容时,,是读(输入)(加载),将文件存储的二进制内容,读入到内存,解析处数据,显示出来;

2.2 标准C库IO和Linux系统lO的关系

在这里插入图片描述

2.3 虚拟地址空间

在这里插入图片描述

2.4 文件描述符

在linux中,一切皆文件
在这里插入图片描述

文件描述符表,前三个描述符是终端的,0~3分别对应标准输入、标准输出、标准错误;
每打开一个新文件,就占用一个当前序号最小的空闲 文件描述符;

比如,新打开a.txt,描述符3;
再打开,b.txt,描述符4;
再打开,c.txt,描述符5;

此时释放,文件b,txt,吗,描述符4空闲了;
再打开,d.txt,这个时候,描述符4;

2.5 Linux系统IO函数(Linux系统api一般也成为系统调用)

Linux系统使用手册 manual ,
查看命令 man ls
查看某一章 man 数字 ls

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
文中是linuxC++动态库 实现接口提供导出的一个例子 注意其中使用函数返回基指针的用法,因为Linux的动态链接库不能像MFC中那样直接导出 一、介绍 如何使用dlopen API动态地加载C++函数和,是Unix C++程序员经常碰到的问题。 事实上,情况偶尔有些复杂,需要一些解释。这正是写这篇mini HOWTO的缘由。 理解这篇文档的前提是对C/C++语言中dlopen API有基本的了解。 这篇HOWTO的维护链接是: http://www.isotton.com/howtos/C++-dlopen-mini-HOWTO/ 二、问题所在 有时你想在运行时加载一个库(并使用其中的函数),这在你为你的程序写一些插件或模块架构的时候经常发生。 在C语言中,加载一个库轻而易举(调用dlopen、dlsym和dlclose就够了),但对C++来说,情况稍微复杂。 动态加载一个C++库的困难一部分是因为C++的name mangling (译者注:也有人把它翻译为“名字毁坏”,我觉得还是不翻译好), 另一部分是因为dlopen API是用C语言实现的,因而没有提供一个合适的方式来装载。 在解释如何装载C++库之前,最好再详细了解一下name mangling。 我推荐您了解一下它,即使您对它不感兴趣。因为这有助于您理解问题是如何产生的,如何才能解决它们。 1. Name Mangling 在每个C++程序(或库、目标文件)中, 所有非静态(non-static)函数在二进制文件中都是以“符号(symbol)”形式出现的。 这些符号都是唯一的字符串,从而把各个函数在程序、库、目标文件中区分开来。 在C中,符号名正是函数名:strcpy函数的符号名就是“strcpy”,等等。 这可能是因为两个非静态函数的名字一定各不相同的缘故。 而C++允许重载(不同的函数有相同的名字但不同的参数), 并且有很多C所没有的特性──比如、成员函数、异常说明──几乎不可能直接用函数名作符号名。 为了解决这个问题,C++采用了所谓的name mangling。它把函数名和一些信息(如参数数量和大小)杂糅在一起, 改造成奇形怪状,只有编译器才懂的符号名。 例如,被mangle后的foo可能看起来像foo@4%6^,或者,符号名里头甚至不包括“foo”。 其中一个问题是,C++标准(目前是[ISO14882])并没有定义名字必须如何被mangle, 所以每个编译器都按自己的方式来进行name mangling。 有些编译器甚至在不同版本间更换mangling算法(尤其是g++ 2.x和3.x)。 即使您搞清楚了您的编译器到底怎么进行mangling的,从而可以用dlsym调用函数了, 但可能仅仅限于您手头的这个编译器而已,而无法在下一版编译器下工作。 三、 使用dlopen API的另一个问题是,它只支持加载函数。 但在C++中,您可能要用到库中的一个,而这需要创建该的一个实例,这不容易做到。 四、解决方案 1. extern "C" C++有个特定的关键字用来声明采用C binding的函数: extern "C" 。 用 extern "C"声明的函数将使用函数名作符号名,就像C函数一样。 因此,只有非成员函数才能被声明为extern "C",并且不能被重载。 尽管限制多多,extern "C"函数还是非常有用,因为它们可以象C函数一样被dlopen动态加载。 冠以extern "C"限定符后,并不意味着函数中无法使用C++代码了, 相反,它仍然是一个完全的C++函数,可以使用任何C++特性和各种型的参数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

R-G-B

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值