![](/img/trans.png)
[英]C : why is that cast of void function to "pointer to function returning pointer to pointer to void" possible
[英]Is it legal to cast a function returning an object pointer to a function returning a void pointer?
這些部分表明調用具有不兼容類型的 function 指針會導致未定義的行為。
C89 3.5.4.3 p9
對於要兼容的兩個 function 類型,兩者都應指定兼容的返回類型。 此外,參數類型列表(如果兩者都存在)應在參數數量和省略號終止符的使用方面達成一致; 相應的參數應具有兼容的類型。
C89 3.5.4.1 p2
對於要兼容的兩種指針類型,兩者都應具有相同的限定,並且都應是指向兼容類型的指針。
C89 3.3.4 p3
指向一種類型的 function 的指針可以轉換為指向另一種類型的 function 的指針,然后再返回; 結果應與原始指針比較。 如果使用轉換后的指針調用 function 的類型與被調用的 function 的類型不兼容,則行為未定義。
從任何其他 object 指針類型轉換為 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; 結果應與原始指針比較。 (具有字符類型的 object 具有最不嚴格的 alignment。)
C89 3.1.2.5 p20
指向 void 的指針應具有與指向字符類型的指針相同的表示形式和 alignment 要求。
C89 3.2.2.3 p1
指向 void 的指針可以轉換為指向任何不完整或 object 類型的指針或從指針轉換。 指向任何不完整或 object 類型的指針可以轉換為指向 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);
}
您問將指向 function 的指針轉換為指向 function 的另一個指針是否合法。 將指向 function 的指針轉換為指向 function 的任何其他指針是合法的。 但是通過這樣的指針調用 function 會調用未定義的行為。 C11 6.5.2.2p9
6.5.2.2 Function 調用
[...]
- 如果 function 定義的類型與表示被調用的 function 的表達式所指向的(表達式的)類型不兼容,則行為未定義。
另一個問題是您的代碼沒有演員表。 它有一個強制分配:
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 *
的表示將不兼容。
如果您只是將 function 指針更改為返回int *
或在調用之前強制轉換的指針,則行為是明確定義的 - 隱式轉換為void *
和顯式轉換為int *
都很好。
IE
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;
或者讓 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.