C调用动态库,windows/linux

来源:互联网 发布:日本旅游注意事项知乎 编辑:程序博客网 时间:2024/05/17 21:07

I. Windows平台下C调用动态库的方法:

Case 1:如果提供了.lib和.dll,则不需要动态加载,因为动态库的.lib中含有dll的所有导出符号

(参考:俞甲子等. 《程序员的自我修养》)

1、假设动态库的源文件Math.c包含一个Add函数,被声明为导出函数(可被库外部调用):

extern "C" __declspec(dllexport) double Add(double a, double b)

{return a+b;}

/*

*

*  extern 表示这是个全局函数,可以供各个其他的函数调用,其实extern没有意义,因为全局函数本来就可以被外部访问。

* “C” 表示编译时按照 C编译器的方式进行编译,而不是C++。 C++的编译方式考虑了函数重载,所以对函数名进行了新的修饰,产生了所谓的破坏性命名。

/*


编译成动态库:cl /LDd(或者/LD,d代表debug版) Math.c

编译生成了Math.dll, Math.obj, Math.exp, Math.lib四个文件


2、使用DLL

/* Test..c*/

#include<stdio.h>

__declspec(dllimprot) double Add(double, double); //声明这个要用的导入函数


int main(int argc, char **argv)

{

 double result = Add(3,2);

 printf("Result = %f\n",result);

 return 0;

}

编译项目代码:cl /c  Test.c

链接动态库: link Test.obj Math.lib

完成生成Test.exe


Case 1:如果仅有.dll,需要显示运行时加载(即LoadLibrary(), GetProcAddress()那一套)

假设还是刚才那个Math.dll,依旧要使用那个定义为导出函数(即__declspec(dllexport))的Add函数

#include<windows.h>

#include<stdio.h>

typedef double (*Func)(double, double);//声明出指向DLL目标函数的函数指针

int main(int argc, char **argv)

{

  Func function;

 //load DLL

 HINSTANCE hinstLib = LoadLibrary("Math.dll");

if (hinstLib == NULL) {printf("Error loading"); return 1;}


// get func address

function = (Func)GetProcAddress(hinstLib, "Add");

if(function == NULL){printf("Error addressing func");FreeLibrary(hinstLib);return 1;}


// call it

int res = function(3.0,3.0);


FreeLibrary(hinstLib);


return 0;

}


II. Linux平台下C调用共享库(.so)的方法:

Case1. 有同时提供.h文件和.so文件

1. 编写foo库

/* foo.h*/

 #ifndef foo_h__
#define foo_h__
extern void foo(void);
#endif  // foo_h__


/* foo.c*/

#include <stdio.h>

void foo(void)
{
   printf("Hello, I'm a shared library");
}


2.制作foo.so库

$gcc -c -Wall -Werror -fpic foo.c -o foo.o

$gcc -shared -o libfoo.so foo.o


3. 代码main.c:

#include <stdio.h>
#include "foo.h" //有.h可用

int main(void)
{
   printf("This is a shared library test...");
    foo();
    return 0;
}


4. 在编译时链接动态库:

$gcc -L/home/username/foo -Wall -o test main.c -lfoo


5. 执行

$export LD_LIBRARY_PATH=/home/username/foo:$LD_LIBRARY_PATH    #添加动态库搜寻路径,因为test的执行需要依赖foo库

$./test


Case2. 仅有.so文件,可以运行时动态加载

#include<stdio.h>

#include<dlfcn.h>

int main(int argc, char* argv[])

{

 void *handle;

 double (*func)(double); //声明出要调用的库中函数

char *error;


// open .so

handle = dlopen("libfoo.so",RTLD_NOW);

if(handle == NULL){printf("Error loading .so");return -1;}


// address the func foo

func = dlsym(handle, "foo");

if( (error=dlerror()) !=NULL){printf("Error addressing func"); dlclose(handle); return -1;}


//call it

foo();

return 0;

}


编译:$gcc -o test test.c -ldl  #-ldl代表链接用于支持动态加载库的动态链接库(DL库)

执行:./test

#可以看出运行时加载的方式 不需要 在编译、执行时指明要用的库(共享对象),只需链接DL库并包含dlfcn.h,用于支持dlopen, dlsym这一套机制。



只有.so,也可以在链接阶段链接.so,本文件中通过声明外部函数来访问

代码文件:

代码main.c:

#include <stdio.h>
//无.h可用


//声明外部函数

extern void foo(void);

int main(void)
{
    printf("This is a shared library test...");
    foo();
    return 0;
}


$gcc test.c libfoo.so -o main  Xlinker -rpath ./ #后面几个参数为链接器指明.so的查找路径


原创粉丝点击