gpt4 book ai didi

c++ - 如果余弦是 fptr,如何解析 *(void **) (&cosine)

转载 作者:太空狗 更新时间:2023-10-29 23:26:16 25 4
gpt4 key购买 nike

找到这个代码示例

void *handle;
double (*cosine)(double);
handle = dlopen("libm.so", RTLD_LAZY);
*(void **) (&cosine) = dlsym(handle, "cos");

我使用从右到左的阅读规则来解析变量的类型:
double (*cosine)(double);

在这里我从左到右写但移动 LTR:“余弦”->“*”->“是一个指针”
然后 "("我们离开最里面的 () 范围 -> "(double)"-> "函数取一个 double"-> 并返回最左边的 "double"

但这是什么鬼?我什至不知道从哪里开始解析)“&cosine”是地址还是引用? (void **) 是什么意思?为什么它最左边的“*”在外面???它是取消引用还是类型?
*(void **) (&cosine)

最佳答案

是的,这是一口。
cosine是一个函数指针。所以&cosine是指向那个指针的指针。然后当我们打一个 *在它前面,我们正在更改原始指针,使其指向其他地方。

它有点像这样:

int i = 5;
int *ip = &i;
*ip = 6; /* changes i to 6 */

或者更像这样:
char a[10], b[10];
char *p = a;
*(&p) = b; /* changes p to point to b */

但在你的情况下,它甚至更棘手,因为 cosine是指向函数的指针,而不是指向数据的指针。大多数情况下,函数指针指向您在程序中定义的函数。但在这里,我们正在安排制作 cosine指向一个动态加载的函数,由 dlsym() 加载功能。
dlsym非常特别,因为它可以返回指向数据的指针,也可以返回指向函数的指针。所以它有一个无法定义的返回类型。它被声明为返回 void * ,当然,因为那是 C 中的“通用”指针类型。(想想 malloc。)但在纯 C 中, void *是通用数据指针类型;它不能保证能够与函数指针一起使用。

最简单的事情就是说
cosine = dlsym(handle, "cos");

但是现代编译器会提示,因为 dlsym返回 void * , 和 cosine有类型 double (*)(double) (即,指向采用 double 并返回 double 的函数的指针),这不是可移植的转换。

所以我们绕过谷仓,设置 cosine间接的值(value),而不是说
cosine = something

而是说
*(&cosine) = something

但这在 dlsym 中仍然没有好处。 case,因为类型仍然不匹配。我们有 void *在右边,所以我们需要 void *在左侧。而解决方法是取地址 &cosine ,否则是指向函数的指针,并将其强制转换为指向指针的指针 void , 或 void ** ,所以当我们打一个 *在它前面我们有一个 void *再次,这是分配 dlsym 的正确目的地的返回值。所以我们最终得到了你问的那一行:
* (void **) (&cosine) = dlsym(handle, "cos");

现在,重要的是要注意我们在这里如履薄冰。我们使用了 &以及为了绕过分配指向- void 的指针这一事实而进行的类型转换指向“函数指针”并不严格合法。在这个过程中,我们成功地消除了编译器警告我们所做的事情并不严格合法。 (实际上,使警告静音正是原始程序员采用这种躲避的意图。)

潜在的问题是,如果数据指针和函数指针具有不同的大小或表示形式怎么办?这段代码用了一些长度来处理函数指针, cosine ,就好像它是一个数据指针,将数据指针的位塞入其中。例如,如果数据指针比函数指针大,这将产生可怕的影响。 (而且,在你问“但是数据指针怎么可能比函数指针大?”之前,这正是它们的情况,例如,在“紧凑”内存模型中,回到 MS-DOS 编程的时代。 )

通常,玩这样的游戏来破坏规则并关闭编译器警告是一个坏主意。在 dlsym的情况下,不过,没关系,我会说完全可以接受。 dlsym不能存在于函数指针与数据指针不同的系统上,因此如果您使用 dlsym总而言之,您必须在所有指针都相同的机器上,并且此代码将起作用。

同样值得一问的是,如果我们在调用 dlsym 时必须使用类型转换来玩游戏吗? ,为什么要使用指针到指针在酒吧周围进行额外的旅行?为什么不直接说
cosine = (double (*)(double))dlsym(handle, "cos");

答案是,我不知道。我很确定这个更简单的转换也能正常工作(同样,只要我们在一个可以存在 dlsym 的系统上)。也许有些编译器会警告这种情况,只能通过使用欺骗者、双指针技巧将其欺骗到沉默状态。

另见 Casting when using dlsym() .

关于c++ - 如果余弦是 fptr,如何解析 *(void **) (&cosine),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46371952/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com