c - 为什么将具有不同参数类型的函数存储到具有 void* 参数 UB 的函数指针?

标签 c function-pointers

我最近偶然发现了一个有趣的问题(至少我认为是)。 一个小例子:

例子

#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/

相关文章:

c - C中对象的函数指针

c - 指针初始化成什么?

c - 将套接字传递给线程而不是 fd?

c - union 嵌套在返回垃圾值的结构中

c++ - 不同的函数有不同的地址吗?

C++ 将函数指针插入内存

c++ - 如何将指向成员函数的指针传递给 C 函数?

将 unsigned char * (uint8_t *) 转换为 const char *

c - C语言中使用汉明码进行单比特纠错双比特错误检测

c++ - 从 MATLAB 调用 c 函数?