我在C中使用的是C,我有一个问题:dlsym()的返回值是否应该显式转换,还是隐式转换正确。以下是功能:
double (*(compile)(void))(double x, double y)
{
if (system("scan-build clang -fPIC -shared -g -Wall -Werror -pedantic "
"-std=c11 -O0 -lm foo.c -o foo.so") != 0) {
exit(EXIT_FAILURE);
}
void *handle;
handle = dlopen("./foo.so", RTLD_LAZY);
if (!handle) {
printf("Failed to load foo.so: %s\n", dlerror());
exit(EXIT_FAILURE);
}
foo f;
f = (foo)dlsym(handle, "foo");
if (!f) {
printf("Failed to find symbol foo in foo.so: %s\n", dlerror());
exit(EXIT_FAILURE);
}
return f;
}函数compile()不接受值,并返回指向一个函数的指针,该函数以两个doubles作为输入,并返回一个双值。然后设置一个系统调用,它编译一个共享对象foo.so。然后,我用foo.so打开dlopen()。然后dlsym()在foo.so中找到foo并返回一个类型为foo的对象,我在标题中将其定义为:
typedef double (*foo)(double, double);我要投dlsym()吗?
发布于 2015-07-20 23:16:31
编写C标准是为了假设指向不同对象类型的指针,特别是指向函数的指针,而不是对象类型,可能有不同的表示形式。这就是为什么通常您不想混合指针,或者如果您做了现代编译器会警告您,如果您想要沉默警告,您通常使用显式强制转换。
另一方面,dlsym的存在假设所有指针都是相同的,因为它应该能够返回指向对象文件中任何数据类型的指针--对象或函数。
换句话说,使用dlsym的代码本质上是不可移植的,因为它不是广泛可移植的,也就是说它“只”可移植到那些所有指针都是安全可转换的机器上。(当然,这几乎是当今所有受欢迎的机器。)
因此,是的,您需要抛出指针来沉默警告,这样做可能会使代码更少地移植到所有指针都不相同的机器(如果警告不被关闭,则会正确地通知您代码将无法工作),但无论如何,dlsym永远不会在这些机器上工作(甚至存在于当前的状态)。
(如果gcc -pedantic警告您从void *到函数指针类型的显式转换,那么除了切换到不同版本的gcc,或者当然不使用-pedantic之外,没有什么可以做的。)
增编:我的回答听起来像是在指针之间转换到不同类型的数据可能是个问题,但这通常是没有问题的。void *类型被很好地定义为泛型数据指针:它是malloc返回的内容,它被定义为可以悄悄地转换为任何对象指针类型--也就是说,您甚至不需要强制转换。因此,对于返回类型的dlsym,它几乎是一个很好的选择,除了函数指针的小问题。malloc从未出现过这个问题(您几乎不会尝试对指向函数的指针进行malloc ),而dlsym总是存在这个问题(您通常试图在动态加载的对象文件中访问的符号是代码,至少它们是数据)。但是函数指针是void *不一定要转换到的,所以您很可能会得到警告,这就是为什么您需要转换,并且您可能会在-pedantic下得到警告,即使是使用这些转换。
发布于 2015-07-21 00:55:01
dlsym()返回一个void*值。这个指针值可以引用对象,也可以引用函数。
如果指向对象,则不需要强制转换,因为C定义了从void*到任何指针到对象类型的隐式转换:
int *ptr = dlsym(handle, "name");如果它指向一个函数(可能更常见),则不存在从void*到任何指针到函数类型的隐式转换,因此必须进行强制转换。
在标准C中,不能保证void*值可以有意义地转换为函数指针。POSIX定义了dlsym(),它隐式地保证dlsym()返回的void*值可以有意义地转换为指针到函数类型--只要目标是对应函数的正确类型。
假设我们处理的是一个没有参数的空函数:
typedef void (*func_ptr_t)(void);
func_ptr_t fptr = (func_ptr_t)dlsym(handle, "name");碰巧的是,gcc (和-pedantic)警告说:
warning: ISO C forbids conversion of object pointer to function pointer type此警告不完全正确。ISO C实际上并不禁止将对象指针转换为函数指针类型。标准列出了几个不可能被强制转换操作符违反的约束;将void*转换为函数指针类型不是其中之一。C标准没有定义这种转换的行为,但是由于POSIX在这种特殊情况下是这样做的,所以这不是一个问题。
对史蒂夫·高峰会的回答的评论表明:
*(void **) (&f) = dlsym(handle, "foo");将沉默gcc的警告。它会这样做,但它所作的假设无论是C还是POSIX都没有保证。POSIX保证dlsym的结果可以转换为函数指针;它不能保证它具有相同的表示或对齐。可能有用,但我不推荐。
https://stackoverflow.com/questions/31526876
复制相似问题