从动态库调用函数?
Calling function from dynamic library?
我正在 Linux 上尝试使用动态库和 C。以下代码将打印错误的输出:
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main(int argc, char **arg)
{
void *dl = dlopen("./lib.so", RTLD_NOW);
if (!dl) {
fprintf(stderr, "ERROR: %s\n", dlerror());
exit(1);
}
char *ver = dlsym(dl, "show_version");
printf("%s\n", ver);
}
如果我进行以下更改,输出将是正确的:
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main(int argc, char **arg)
{
void *dl = dlopen("./lib.so", RTLD_NOW);
if (!dl) {
fprintf(stderr, "ERROR: %s\n", dlerror());
exit(1);
}
char *(*ver)() = dlsym(dl, "show_version");
printf("%s\n", ver());
}
我不确定 char *(*ver)()
在做什么以及为什么需要它?谁能解释一下?
dlsym
- 获取共享对象或可执行文件中符号的地址
这意味着当您执行 dlsym(dl, "show_version");
时,您实际上并没有调用共享库中的函数 show_version
。您获得该函数的地址 - 可用于反复调用该函数。
要“解码”char *(*ver)()
的含义,您可以使用通常所说的 Clockwise/Spiral Rule
+-----+
| V
char* (*ver) () ver is a
^ ^ | | pointer to
| | | | a function (taking no arguments)
| +-+ | returning char*
| |
+------------+
我假设以上内容与您放入共享库中的 show_version
函数的签名匹配。示例:
// a function (taking no arguments), returning a char*
char *show_version(void) {
static char version[] = "1.0";
return version;
}
第一次尝试使用相同的规则,char* ver
:
char* ver
^ | ver is a
| | char*
+----+
您需要一个指向函数的指针(具有正确的签名)才能调用该函数并获得您想要的结果。您不能调用 char*
,当您调用 printf("%s\n", ver);
时,它只会开始读取地址(存储函数的位置)的内存,直到找到空终止符。你可能看到的只是乱码。
另一方面,如果你有一个合适的函数指针,你可以像你注意到的那样,用 ver()
调用它指向的函数,你会在 [=45 中得到一个 char*
=] 指向动态加载函数的字符串 returned.
您还可以在不涉及共享库的情况下在程序中使用函数指针。
#include <stdio.h>
long foo(short x, int y) {
return x + y;
}
int main() {
long(*foo_ptr)(short, int) = foo;
// foo_ptr is a pointer to a function taking (short, int) as
// arguments and returning a long
printf("%ld\n", foo(1, 2) ); // prints 3
printf("%ld\n", foo_ptr(1, 2) ); // also prints 3
}
dlsym(dl, "show_version")
returns 符号 show_version
的地址。因为show_version
是一个函数,所以就是函数的地址。
char *ver = dlsym(…);
把那个指针放在一个char *
里面,基本没什么用。指向函数的指针不指向对打印有用的字节。然后 printf("%s\n", ver);
说要打印 ver
指向的字节,就好像它们是一个字符串一样。但是字节有(在典型的 C 实现中)函数的机器代码。它们不是您要打印的字符串的字节。
char *(*ver)() = dlsym(…);
将 ver
定义为指向未指定参数且 returns 为 char *
的函数的指针。要查看此内容:
char <i>something</i>
声明 <i>something</i>
到成为 char
.
char *<i>something</i>
声明 <i>something</i>
成为指向 char
. 的指针
char *<i>something</i>()
声明 <i>something</i>
成为未指定参数的函数 returns 指向 char
. 的指针
char *(*<i>something</i>)()
声明 <i>something</i>
指向此类函数的指针。
然后,在printf("%s\n", ver());
,ver()
调用这个函数。 char *
它 returns 传递给 printf
进行打印。
我正在 Linux 上尝试使用动态库和 C。以下代码将打印错误的输出:
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main(int argc, char **arg)
{
void *dl = dlopen("./lib.so", RTLD_NOW);
if (!dl) {
fprintf(stderr, "ERROR: %s\n", dlerror());
exit(1);
}
char *ver = dlsym(dl, "show_version");
printf("%s\n", ver);
}
如果我进行以下更改,输出将是正确的:
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main(int argc, char **arg)
{
void *dl = dlopen("./lib.so", RTLD_NOW);
if (!dl) {
fprintf(stderr, "ERROR: %s\n", dlerror());
exit(1);
}
char *(*ver)() = dlsym(dl, "show_version");
printf("%s\n", ver());
}
我不确定 char *(*ver)()
在做什么以及为什么需要它?谁能解释一下?
dlsym
- 获取共享对象或可执行文件中符号的地址
这意味着当您执行 dlsym(dl, "show_version");
时,您实际上并没有调用共享库中的函数 show_version
。您获得该函数的地址 - 可用于反复调用该函数。
要“解码”char *(*ver)()
的含义,您可以使用通常所说的 Clockwise/Spiral Rule
+-----+
| V
char* (*ver) () ver is a
^ ^ | | pointer to
| | | | a function (taking no arguments)
| +-+ | returning char*
| |
+------------+
我假设以上内容与您放入共享库中的 show_version
函数的签名匹配。示例:
// a function (taking no arguments), returning a char*
char *show_version(void) {
static char version[] = "1.0";
return version;
}
第一次尝试使用相同的规则,char* ver
:
char* ver
^ | ver is a
| | char*
+----+
您需要一个指向函数的指针(具有正确的签名)才能调用该函数并获得您想要的结果。您不能调用 char*
,当您调用 printf("%s\n", ver);
时,它只会开始读取地址(存储函数的位置)的内存,直到找到空终止符。你可能看到的只是乱码。
另一方面,如果你有一个合适的函数指针,你可以像你注意到的那样,用 ver()
调用它指向的函数,你会在 [=45 中得到一个 char*
=] 指向动态加载函数的字符串 returned.
您还可以在不涉及共享库的情况下在程序中使用函数指针。
#include <stdio.h>
long foo(short x, int y) {
return x + y;
}
int main() {
long(*foo_ptr)(short, int) = foo;
// foo_ptr is a pointer to a function taking (short, int) as
// arguments and returning a long
printf("%ld\n", foo(1, 2) ); // prints 3
printf("%ld\n", foo_ptr(1, 2) ); // also prints 3
}
dlsym(dl, "show_version")
returns 符号 show_version
的地址。因为show_version
是一个函数,所以就是函数的地址。
char *ver = dlsym(…);
把那个指针放在一个char *
里面,基本没什么用。指向函数的指针不指向对打印有用的字节。然后 printf("%s\n", ver);
说要打印 ver
指向的字节,就好像它们是一个字符串一样。但是字节有(在典型的 C 实现中)函数的机器代码。它们不是您要打印的字符串的字节。
char *(*ver)() = dlsym(…);
将 ver
定义为指向未指定参数且 returns 为 char *
的函数的指针。要查看此内容:
char <i>something</i>
声明<i>something</i>
到成为char
.char *<i>something</i>
声明<i>something</i>
成为指向char
. 的指针
char *<i>something</i>()
声明<i>something</i>
成为未指定参数的函数 returns 指向char
. 的指针
char *(*<i>something</i>)()
声明<i>something</i>
指向此类函数的指针。
然后,在printf("%s\n", ver());
,ver()
调用这个函数。 char *
它 returns 传递给 printf
进行打印。