简体   繁体   English

将 function 返回到 function 返回 void 指针的 object 指针是否合法?

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

These sections indicate that calling a function pointer with a not compatible type results in undefined behavior.这些部分表明调用具有不兼容类型的 function 指针会导致未定义的行为。

C89 3.5.4.3 p9 C89 3.5.4.3 p9

For two function types to be compatible, both shall specify compatible return types .对于要兼容的两个 function 类型,两者都应指定兼容的返回类型 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 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 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;指向一种类型的 function 的指针可以转换为指向另一种类型的 function 的指针,然后再返回; 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.如果使用转换后的指针调用 function 的类型与被调用的 function 的类型不兼容,则行为未定义。

Is it compatible to cast from any other object pointer type to a void pointer?从任何其他 object 指针类型转换为 void 指针是否兼容?

C89 3.3.4 p3 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; 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.) (具有字符类型的 object 具有最不严格的 alignment。)

C89 3.1.2.5 p20 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.指向 void 的指针应具有与指向字符类型的指针相同的表示形式和 alignment 要求。

C89 3.2.2.3 p1 C89 3.2.2.3 p1

A pointer to void may be converted to or from a pointer to any incomplete or object type.指向 void 的指针可以转换为指向任何不完整或 object 类型的指针或从指针转换。 A pointer to any incomplete or object type may be converted to a pointer to void and back again;指向任何不完整或 object 类型的指针可以转换为指向 void 的指针并再次返回; the result shall compare equal to the original pointer.结果应与原始指针比较。

Example:例子:

#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);
}

You ask if it is legal to cast a pointer to a function to another pointer to a function.您问将指向 function 的指针转换为指向 function 的另一个指针是否合法。 It is legal to cast a pointer to a function to any other pointer to a function.将指向 function 的指针转换为指向 function 的任何其他指针是合法的。 But calling the function through such a pointer invokes undefined behavior.但是通过这样的指针调用 function 会调用未定义的行为。 C11 6.5.2.2p9 C11 6.5.2.2p9

6.5.2.2 Function calls 6.5.2.2 Function 调用

[...] [...]

  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.如果 function 定义的类型与表示被调用的 function 的表达式所指向的(表达式的)类型不兼容,则行为未定义。

Another problem is that your code does not have a cast .另一个问题是您的代码没有演员表。 It has a forced assignment:它有一个强制分配:

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

This is invalid, having a constraint violation, that a C compiler must diagnose.这是无效的,违反了约束,C 编译器必须诊断。 A cast would read演员会读

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

Now the question is what is the behaviour of现在的问题是

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

The behaviour of the construct is undefined as per the standard.根据标准未定义构造的行为。 Of course your implementation is free to provide a meaning to the expression.当然,您的实现可以自由地为表达式提供含义。 You should check your compiler manuals for the behaviour in this case.在这种情况下,您应该检查您的编译器手册以了解该行为。

There have been architectures where the representation for void * and int * would not have been compatible.有些架构中void *int *的表示将不兼容。


If you just change the function pointer to one returning an int * or cast back before calling, the behaviour is well-defined - the implicit conversion to void * and explicit cast to int * are both fine.如果您只是将 function 指针更改为返回int *或在调用之前强制转换的指针,则行为是明确定义的 - 隐式转换为void *和显式转换为int *都很好。

Ie IE

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

or或者

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

Or let the function return void * :或者让 function 返回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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM