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

4
这些章节表明,使用不兼容的类型调用函数指针将导致未定义的行为。
C89 3.5.4.3 p9
两个函数类型要兼容,都必须指定兼容的返回类型。此外,如果两个参数类型列表都存在,则在参数数量和省略号终止符的使用方面应保持一致;相应参数的类型应兼容。
C89 3.5.4.1 p2
要使两个指针类型兼容,它们都必须具有相同的限定符,并且都必须是指向兼容类型的指针。
C89 3.3.4 p3
一个指向某种类型的函数的指针可以转换为指向另一种类型的函数的指针,反之亦然;结果应与原始指针相等。如果使用转换后的指针调用具有不兼容类型的被调用函数,则行为未定义。
将其他对象指针类型强制转换为void指针是否兼容?
C89 3.3.4 p3
然而,保证给定对齐方式的对象的指针可以被转换为具有相同或较少严格对齐要求的对象的指针,然后再转换回来;结果应与原始指针相等(具有字符类型的对象具有最不严格的对齐方式)。
C89 3.1.2.5 p20
指向void的指针应具有与字符类型的指针相同的表示和对齐要求。
C89 3.2.2.3 p1
可以将指向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);
}

int *(*fn_ptr)(void) = foo; 的翻译是什么? - David C. Rankin
1个回答

11

您问是否可以将函数指针转换为另一个函数指针,这是合法的。但是通过这样的指针调用函数会导致未定义的行为。

C11 6.5.2.2第9段

另一个问题是您的代码没有进行强制转换,而是进行了强制赋值:

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;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接