c-将返回对象指针的函数强制转换为返回空指针的函数合法吗



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

C89 3.5.4.3 p9

对于要兼容的两种函数类型,两者都应指定兼容的返回类型。此外,参数类型列表(如果两者都存在(应在参数数量和省略号终止符的使用方面达成一致;相应的参数应具有兼容的类型。

C89 3.5.4.1 p2

对于要兼容的两个指针类型,两者都应具有相同的限定,并且都应是指向兼容类型的指针。

C89 3.3.4 p3

指向一种类型的函数的指针可以转换为指向另一种类型函数的指针并再次返回;结果应与原始指针进行比较如果转换后的指针用于调用类型与被调用函数的类型不兼容的函数,则行为是未定义的

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

C89 3.3.4 p3

然而,可以保证的是,指向给定对齐对象的指针可以转换为指向相同对齐或不太严格对齐的对象的指针,然后再返回;结果应与原始指针进行比较。(具有字符类型的对象具有最不严格的对齐。(

C89 3.1.2.5 p20

指向void的指针应具有与指向字符类型的指针相同的表示和对齐要求。

C89 3.2.2.3 p1

指向void的指针可以转换为指向任何不完整类型或对象类型的指针,也可以从该指针转换为指向任意不完整类型的指针指向任何不完整或对象类型的指针都可以转换为指向void并返回的指针;结果应与原始指针进行比较

示例:

#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("%dn", data);
}

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

6.5.2.2函数调用

[…]

  1. 如果函数定义的类型与表示被调用函数的表达式所指向的(表达式的(类型不兼容,则行为未定义

另一个问题是您的代码没有强制转换。它有一个强制任务:

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 *的表示将不兼容。


如果在调用之前只将函数指针更改为返回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;

或者让函数返回void *:

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;

最新更新