Jas*_*own 4 c casting function-pointers c89 language-lawyer
这些部分指示以不兼容的类型调用函数指针会导致未定义的行为。
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("%d\n", data);
}
Run Code Online (Sandbox Code Playgroud)
Ant*_*ala 10
您询问将一个函数的指针强制转换为另一个函数的指针是否合法。将指向函数的指针转换为指向函数的任何其他指针是合法的。但是通过这样的指针调用函数会调用未定义的行为。C11 6.5.2.2p9
6.5.2.2函数调用
[...]
- 如果函数定义的类型与表示被调用函数的表达式所指向的类型(表达式的类型)不兼容,则行为是不确定的。
另一个问题是您的代码没有强制转换。它具有强制分配:
void *(*fn_ptr)(void) = foo;
Run Code Online (Sandbox Code Playgroud)
这是无效的,具有约束冲突,C编译器必须诊断。演员会读
void *(*fn_ptr)(void) = (void *(*)(void))foo;
Run Code Online (Sandbox Code Playgroud)
现在的问题是
void *(*fn_ptr)(void) = (void *(*)(void))foo;
void *raw = fn_ptr();
int data = *(int *)raw;
Run Code Online (Sandbox Code Playgroud)
根据标准未定义构造的行为。当然,您的实现可以自由地为表达式提供含义。在这种情况下,应检查编译器手册中的行为。
已有架构,其中的代表void *,并int *
不会一直兼容。
如果只是int *在调用之前将函数指针更改为返回an 或强制转换的指针,则行为是明确定义的-隐式转换为void * 和显式转换为int *都很好。
即
int *(*fn_ptr)(void) = foo;
void *raw = fn_ptr();
int data = *(int *)raw;
Run Code Online (Sandbox Code Playgroud)
要么
void *(*fn_ptr)(void) = (void *(*)(void))foo;
void *raw = ((int *(*)(void))fn_ptr)();
int data = *(int *)raw;
Run Code Online (Sandbox Code Playgroud)
或者让函数返回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;
Run Code Online (Sandbox Code Playgroud)