C语言三方库的调用和编写

27 篇文章 0 订阅

来源:https://www.jianshu.com/p/d7c516f7433e

1. 三方库相关指令

gcc -l

l 参数就是用来指定程序要链接的库,-l 参数紧接着就是库名,那么库名跟真正的库文件名有什么关系呢?就拿数学库来说,他的库名是 m,他的库文件名是 libm.so,很容易看出,把库文件名的头lib 和尾 .so 去掉就是库名了。好了现在我们知道怎么得到库名, 当我们自已要用到一个第三方提供的库名字 libtest.so,那么我们只要把 libtest.so 拷贝到 /usr/lib 里,编译时加上 -ltest 参数,我们就能用上 libtest.so 库了(当然要用 libtest.so 库里的函数,我们还需要与 libtest.so 配套的头文件)

gcc -L

放在/lib 和 /usr/lib 和 /usr/local/lib里的库直接用-l参数就能链接了,但如果库文件没放在这三个目录里,而是放在其他目录里,这时我们只用-l参数的话,链接还是会出错,出错信息大概是:“/usr/bin/ld: cannot find -lxxx”,也就是链接程序 ld 在那3个目录里找不到libxxx.so。这时另外一个参数-L就派上用场了,比如常用的X11 的库,它在 /usr/X11R6/lib 目录下,我们编译时就要用 -L/usr/X11R6/lib -lX11 参数,-L 参数跟着的是库文件所在的目录名。再比如我们把libtest.so 放在/aaa/bbb/ccc 目录下,那链接参数就是 -L/aaa/bbb/ccc -ltest

gcc -I

I 参数是用来指定头文件目录,/usr/include 目录一般是不用指定的,gcc 知道去那里找,但是如果头文件不在 /usr/include 里我们就要用 -I 参数指定了,比如头文件放在/myinclude 目录里,那编译命令行就要加上 -I/myinclude 参数了,如果不加你会得到一个 “xxxx.h: No such file or directory” 的错误。-I 参数可以用相对路径,比如头文件在当前目录,可以用 -I. 来指定。

gcc –shared

shared该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件

gcc -fPIC

fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。

使用ar 命令创建或者操作静态库
ar archivefile objfile

archivefile:archivefile 是静态库的名称

objfile:objfile 是已.o 为扩展名的中间目标文件名,可以多个并列参数 意义

-r 将objfile 文件插入静态库尾或者替换静态库中同名文件

-x 从静态库文件中抽取文件objfile

-t 打印静态库的成员文件列表

-d 从静态库中删除文件objfile

-s 重置静态库文件索引

-v 创建文件冗余信息

-c 创建静态库文件

2. 调用三方库

使用数学库libm 举例

编译:gcc -g -Wall -o test1 test1.c –lm

通过l 指令,将libm 链接进程序

[root@izbp1e2kit9gbr3xm1zerrz clib]# ./test1 The cosine of 60.000000
degrees is 0.500000.

[root@izbp1e2kit9gbr3xm1zerrz clib]# find / -name “libm*”|grep
libm*.so

/usr/lib/i686/nosegneg/libm.so.6

/usr/lib/libm.so.6

/usr/lib64/libm.so.6

/usr/lib64/libm.so

/usr/share/ltrace/libm.so.conf [root@izbp1e2kit9gbr3xm1zerrz clib]#
ldd ldd: missing file arguments

Try `ldd --help’ for more information. [root@izbp1e2kit9gbr3xm1zerrz
clib]# ldd test1

linux-vdso.so.1 => (0x00007ffd6716e000)

libm.so.6 => /lib64/libm.so.6 (0x00007f8d4da70000) libc.so.6 =>
/lib64/libc.so.6 (0x00007f8d4d6a3000)

/lib64/ld-linux-x86-64.so.2 (0x00007f8d4dd7d000)

#include <stdio.h> 
#include <stdlib.h>
#include <pthread.h>
#include <sys/syscall.h>
#include <sys/types.h>

#define MAX_NUM 1000

// thread callback

static void* _run(void* arg) { int piyo = 10;

char* name = (char*)arg; int i;

for(i = 0; i < MAX_NUM; ++i) {

printf("[thread %u]: <%d, hi!> from %s\n", syscall(SYS_gettid), i,

name);

sleep(1);

}

return NULL;

}

#define _INT_PTX (3)

char* thread_name[] = {"A", "B", "C", "D", "E", "F", "G", "H"};

int main(void) { int i;

pthread_t tx[_INT_PTX];

puts("main beign");

printf("main thread id :%u\n",/*syscall(SYS_gettid)*/getpid());

for(i=0; i<_INT_PTX; ++i) {

//create threads

rt = pthread_create(tx+i, NULL, _run, thread_name[i]); if(rt < 0) {

printf("pthread_create create error! rt = %d, i=%d\n", rt, i); break;

}

}

for(i=0; i<_INT_PTX; ++i) { pthread_join(tx[i], NULL);

}

puts("end");

return 0;

}

编译命令

gcc -Wall -g -o FightingSaintBuddha.out FightingSaintBuddha.c -lpthread

3. 编写三方库

linux 下有两种库:动态库和静态库(共享库) 二者的不同点在于代码被载入的时刻不同。

静态库的代码在编译过程中已经被载入可执行程序,因此体积比较大。

动态库(共享库)的代码在可执行程序运行时才载入内存,在编译过程中仅简单的引用,因此代码体积比较小。

不同的应用程序如果调用相同的库,那么在内存中只需要有一份该动态库(共享库)的实例。

静态库和动态库的最大区别,静态情况下,把库直接加载到程序中,而动态库链接的时候,它只是保留接口,将动态库与程序代码独立,这样就可以提高代码的可复用度,和降低程序的耦合度。

静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。

动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在

自己编写动态库

不同的UNIX 系统,链接动态库方法,实现细节不一样

编译PIC 型.o 中间文件的方法一般是采用 C 语言编译器的-KPIC 或者-fpic 选项,有的

UNIX 版本C语言编译器默认带上了PIC标准.创建最终动态库的方法一般采用C语言编译器的-G或者-shared选项,或者直接使用工具ld创建。

最主要的是GCC 命令行的一个选项:

-shared该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件

-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。

-L.:表示要连接的库在当前目录中

-ltest:编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上 lib,后面加上.so 来确定库的名称

LD_LIBRARY_PATH:这个环境变量指示动态连接器可以装载动态库的路径。当然如果有 root 权限的话,可以修改/etc/ld.so.conf 文件,然后调用

/sbin/ldconfig 来达到同样的目的,不过如果没有 root 权限,那么只能采用输出

LD_LIBRARY_PATH 的方法了。

#ifndef  CACULATE_HEAD   #define  CACULATE_HEAD

//add

int add(int a, int b); int sub(int a, int b); int div(int a, int b); int mul(int a, int b);

#endif

#include "caculate.h"

int add(int a, int b)

{

return (a+b);

}

编译生成 so

gcc -g -Wall -shared -fpic caculate.c -o libcac.so

gcc -g Wall test2.c -o test2 -L./-lcac

gcc -g -Wall test3.c -o test3.out -lbl

自己编写静态库

使用ar命令创建或者操作静态库

gcc -o caculate.o -c caculate.c

ar -rcs libcac.a caculate.o

gcc -g -Wall test2.c -o test4.out -L.libcac.a

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Rust和C语言的相互调用过程中,指针是一个重要的概念。Rust是一种较新的系统级编程语言,具备了内存安全和高性能的特性,而C语言作为一种传统的系统性语言,其指针的概念在Rust中也可以得到支持和使用。 在Rust中,可以使用`ffi`(Foreign Function Interface)功能来与C语言进行交互。这使得Rust可以使用C语言函数和数据结构。在C语言中,指针用于引用内存中的数据地址。而在Rust中,由于其内存管理的安全性,需要使用特定的语法和关键字来操作和使用指针。 在Rust中,使用`&`和`*`两个符号来进行指针操作。使用`&`可以创建一个指向某个值的引用,并且由Rust自动处理内存的管理。而使用`*`可以通过解引用操作符来取得指针所指向的值。 当Rust与C语言进行相互调用时,指针在两者之间的传递非常重要。在Rust调用C函数时,需要通过`*const`或`*mut`等类型来声明指针。同时,通过`unsafe`关键字来告诉编译器这是一个不安全的操作,需要手动去管理指针所指向的内存。 在C调用Rust函数时,需要考虑Rust的所有权(ownership)机制。Rust的所有权机制确保了内存的安全和有效的内存管理。当C语言调用Rust函数时,需要传递指针给Rust函数,并在合适的时候将指针的所有权返回给C语言。 总之,Rust和C语言的相互调用中,指针是连接两者的重要桥梁。在Rust中,通过特定的语法和关键字进行指针操作,并通过`ffi`功能与C语言进行交互。指针的有效管理是确保内存安全的关键所在。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值