我最近偶然发现了一个有趣的问题(至少我认为是)。 一个小例子:
例子
#include <stdio.h>
typedef struct A {
int x;
} A;
int (*func)(void*, void*);
int comp(A* a, A* b) {
return a->x - b->x;
}
int main() {
func = comp;
A a;
A b;
a.x = 9;
b.x = 34;
printf("%d > %d ? %s\n", a.x, b.x, func(&a, &b) > 0 ? "true" : "false");
}
我问自己上面显示的代码是否有效,但在编译时 GCC 发出警告:warning: assignment from incompatible pointer type
。我做了一些研究,并在一个线程中 someone stated the above would be undefined behaviour现在我很好奇为什么这是 UB,因为 void*
可以安全地转换为任何可能的其他类型。这只是标准说法“不,那是未定义的”还是有一些可以解释的原因?我在 StackOverflow 上发现的所有问题都说明了它的 UB,但没有确切说明原因。也许它与如何在内部取消引用函数指针有关?
最佳答案
void *
可以安全地转换为任何其他类型或从任何其他类型转换,但这不是您要尝试进行的转换。您正在尝试将 int (*)(A *, A *)
转换为 int (*)(void *, void*)
。这是两个截然不同的事情。
void *
的自动转换不适用于函数指针中的参数。要使两个函数指针兼容,参数的数量和类型以及返回类型必须兼容。
其中一个原因是 void *
不需要与其他类型的指针具有相同的表示形式。这在简单地转换为标准明确允许的 void *
和返回时很好,但是在调用函数时可能会出现问题。
假设一个void *
用8个字节表示,一个struct指针用4个字节表示。在您的示例中,两个 8 字节的值将被压入堆栈,但两个 4 字节的值将从堆栈中读取作为函数中的参数。这将导致无效的指针值,这些值随后将被取消引用。
关于c - 为什么将具有不同参数类型的函数存储到具有 void* 参数 UB 的函数指针?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56480191/