将返回对象指针的函数强制转换为返回 void 指针的函数是否合法?

Is it legal to cast a function returning an object pointer to a function returning a void pointer?

这些部分表明调用具有不兼容类型的函数指针会导致未定义的行为。

C89 3.5.4.3 p9

For two function types to be compatible, both shall specify compatible return types. Moreover, the parameter type lists, if both are present, shall agree in the number of parameters and in use of the ellipsis terminator; corresponding parameters shall have compatible types.

C89 3.5.4.1 p2

For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types.

C89 3.3.4 p3

A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer. If a converted pointer is used to call a function that has a type that is not compatible with the type of the called function, the behavior is undefined.

从任何其他对象指针类型转换为 void 指针是否兼容?

C89 3.3.4 p3

It is guaranteed, however, that a pointer to an object of a given alignment may be converted to a pointer to an object of the same alignment or a less strict alignment and back again; the result shall compare equal to the original pointer. (An object that has character type has the least strict alignment.)

C89 3.1.2.5 p20

A pointer to void shall have the same representation and alignment requirements as a pointer to a character type.

C89 3.2.2.3 p1

A pointer to void may be converted to or from a pointer to any incomplete or object type. A pointer to any incomplete or object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.

示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int *foo(void) {
    int *data = malloc(sizeof(int));
    *data = 42;
    return data;
}

int main(int argc, char *argv[]) {
    void *(*fn_ptr)(void) = foo;
    void *raw = fn_ptr();
    int data = *(int *)raw;
    printf("%d\n", data);
}

你问将一个函数指针转换为另一个函数指针是否合法。将指向函数的指针转换为任何其他指向函数的指针是合法的。但是通过这样的指针调用函数会调用未定义的行为。 C11 6.5.2.2p9

6.5.2.2 Function calls

[...]

  1. If the function is defined with a type that is not compatible with the type (of the expression) pointed to by the expression that denotes the called function, the behavior is undefined.

另一个问题是您的代码没有 cast。它有一个强制分配:

void *(*fn_ptr)(void) = foo;

这是无效的,存在约束冲突,C 编译器必须对其进行诊断。演员会读

void *(*fn_ptr)(void) = (void *(*)(void))foo;

现在的问题是

的行为是什么
void *(*fn_ptr)(void) = (void *(*)(void))foo;
void *raw = fn_ptr();
int data = *(int *)raw;

构造的行为未根据标准定义。当然,您的实现可以自由地为表达式提供含义。您应该检查您的编译器手册以了解这种情况下的行为。

有些架构中 void *int * 的表示 本来就不兼容。


如果您只是将函数指针更改为一个 returning 一个 int * 或在调用之前强制转换,行为是明确定义的 - 隐式转换为 void * 和显式转换为 int * 都很好。

int *(*fn_ptr)(void) = foo;
void *raw = fn_ptr();
int data = *(int *)raw;

void *(*fn_ptr)(void) = (void *(*)(void))foo;
void *raw = ((int *(*)(void))fn_ptr)();
int data = *(int *)raw;

或者让函数returnvoid *:

void *foo(void) {
    int *data = malloc(sizeof(int));
    *data = 42;
    return data;
}

void *(*fn_ptr)(void) = foo;
void *raw = fn_ptr();
int data = *(int *)raw;