我想知道我們是否可以創建一個通用函式指標,它將指向一個在 C 中具有任何回傳型別的函式。我通過以下代碼進行了嘗試:
typedef void (*func_ptr)(int, int);
int func1(int a, int b) {
return a * b;
}
int func2(int a, int b) {
return a b;
}
int main() {
func_ptr ptr1, ptr2;
ptr1 = func1;
ptr2 = func2;
printf("Func1: %d\n", *(int *)(*ptr1)(4, 5));
printf("Func2: %d\n", *(int *)(*ptr2)(4, 5));
return 0;
}
如果func_ptr是 type int,則代碼將起作用。但是這種方法有什么問題呢?為什么我們不能將void *指標分配給整數函式?
uj5u.com熱心網友回復:
如果
func_ptr是 typeint,則代碼將起作用
更準確地說:如果func_ptr型別定義指定了回傳型別int,初始化代碼將是正確的,但呼叫仍然無效,因為*(int *)不能應用于void回傳值并且使用不同于其呼叫約定的原型呼叫函式未定義反正行為。func_ptr應該強制((int(*)(int, int))func_ptr)轉換為正確的呼叫。
沒有泛型函式指標之類的東西,但是一個不帶引數并回傳的函式void是盡可能接近的。只要您使用正確的轉換,具有不同原型的函式可以存盤到不兼容的函式指標中,并且必須將指標轉換回它在呼叫站點指向的函式的確切原型。這對 C 來說是可能的,但對 C 來說更棘手。
請注意,函式呼叫是后綴操作,因此它的系結比前綴操作(例如 cast:)強(int(*)(int, int))func_ptr(3, 4)。你必須寫:
((int(*)(int, int))func_ptr)(3, 4)
這是修改后的版本:
#include <stdio.h>
// define a generic function pointer of no arguments with no return value
typedef void (*func_ptr)(void);
// actual function type: function of taking 2 ints, returning an int
typedef int (*func_of_int_int_retuning_int)(int, int);
int func1(int a, int b) {
return a * b;
}
int func2(int a, int b) {
return a b;
}
int main() {
func_ptr ptr1, ptr2;
// use explicit casts for assignment (with or without the typedef)
ptr1 = (func_ptr)func1;
ptr2 = (void (*)(void))func2;
// at call sites, the function pointer must be cast back to the actual
// type for invocation with arguments and handling of return value
// again you can use a typedef or not
printf("Func1: %d\n", ((int (*)(int, int))ptr1)(4, 5));
printf("Func2: %d\n", ((func_of_int_int_retuning_int)ptr2)(4, 5));
return 0;
}
uj5u.com熱心網友回復:
您可以在不同的函式指標之間進行轉換,但不允許呼叫函式指標,除非它與指向的型別兼容。您可以使用強制轉換強制編譯分配(這會給您一個警告),但是一旦您嘗試呼叫ptr1或ptr2您得到未定義的行為。
如果您首先將它們轉換回正確的函式型別,則可以呼叫它們。這是對的:
typedef void (*func_ptr) (int, int); // literally any function type would work
typedef int (*real_func_ptr) (int, int);
int func1(int a, int b) { return a * b; }
int func2(int a, int b) { return a b; }
int main() {
func_ptr ptr1, ptr2;
ptr1 = (func_ptr) func1;
ptr2 = (func_ptr) func2;
int a = ((real_func_ptr)ptr1)(4, 5);
int b = ((real_func_ptr)ptr2)(4, 5);
return a b;
}
關于你的帖子還有幾點:
我經常看到這種情況,學生說“void function”和“int function”,好像函式型別是它的回傳型別。這是錯誤的并且非常具有誤導性。函式型別是:“函式采用兩個 int 型別的引數并回傳 int”(又名
int (int, int))您的 typedef 是:指向帶有 2 個 int 引數并回傳的函式的指標
void。它不回來了void *。
uj5u.com熱心網友回復:
沒有類似于void*物件指標的通用函式指標型別。但是,C 標準實際上保證了我們可以在任意兩個函式指標之間相互轉換,只要我們通過正確型別的函式指標呼叫函式。這意味著任何函式指標型別實際上都可以用作通用函式指標型別。
這幾行有很多問題:*(int *)(*ptr1)(4, 5).
- 您可能不會呼叫
ptr1,因為它是 typevoid(*)(int,int),但它指向 type 的函式int(*))(int, int)。您需要在呼叫之前轉換回正確的型別。(可以使用像列舉這樣的單獨變數來跟蹤指標實際指向的型別。) - 無論哪種方式,
*(int *)演員都會在函式呼叫之后轉換結果,所以它不會做你想要的。
使用函式指標進行泛型編程通常涉及確定某種函式型別以用作模板,然后相應地實作所有函式。
或者我們可以_Generic在宏內部使用在編譯時對型別進行分類,例如:
#define func(x,y) \
_Generic((x), int: _Generic((y), int: int_func, default: 0), \
char*: _Generic((y), char*: string_func, default: 0) ) (x,y)
int main (void)
{
printf("Func1: %d\n", func(4,5));
printf("Func2: %s\n", func("hello","world"));
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/494544.html
