2017-02-01 178 views
1

我目前正面臨着一個非常惱人的問題好傢伙:函數指針鑄造

我正在寫使用函數指針的作品回調管理器的系統,現在考慮到現在爲止我已經分配的事實void函數指針指向一些其他非void函數指針,我已經意識到它實際上不允許它。

此刻我正在考慮投射void指針,以便匹配我爲我的原型函數每個回調,但我不明白如何執行鑄造

它是可行的,還是我應該採用另一種解決方案?

目前這些都是我的回調容器及其類型定義:

typedef void modbus_read_t(unsigned int uid, unsigned int address, unsigned int count, char* response); 
typedef void modbus_write_t(unsigned int uid, unsigned int address, unsigned int *data, char* response); 

typedef void system_read_t(unsigned int uid, unsigned int var_number, unsigned int count, char* response); 
typedef void system_write_t(unsigned int uid, unsigned int var_number, struttura_system *storage, char* response); 

void (*M_callbacks_r[3]) (unsigned int uid, unsigned int address, unsigned int count, char* response); 
void (*M_callbacks_w[2]) (unsigned int uid, unsigned int address, unsigned int *data, char* response); 
void (*P_callbacks_r[2]) (unsigned int uid, unsigned int var_number, unsigned int count, char* response); 
void (*P_callbacks_w[2]) (unsigned int uid, unsigned int var_number, struttura_system *storage, char* response); 

這是功能的,其登記回調原型:

void registerCallback(int systemType,int operationType, void (callback)(void*)); 

了什麼做的是投void (callback)(void*)到上面的typedefs之一。

+0

請注意,使用空的參數列表,如在接受答案,是一個過時的功能,這意味着它可能會在將來的語言被刪除。過時的功能不應該使用,並留在用於向後兼容的語言中。 – 2501

回答

2

那麼,鑄件應該工作。 C標準允許在函數指針類型之間進行轉換,唯一不應該做的就是通過函數指針調用具有錯誤原型的函數,即在調用之前將其轉換回正確的原型,以避免未定義的行爲。

讓我們通過簡化您的陣列一點,爲便於閱讀的緣故開始:

modbus_read_t* M_callbacks_r[2]; 
modbus_write_t* M_callbacks_w[2]; 
system_read_t* P_callbacks_r[2]; 
system_write_t* P_callbacks_w[2]; 

我不知道爲什麼你typedef編的功能類型,而不是函數指針類型,但我會走它。

現在registerCallback可以如下實施:

void registerCallback(int systemType,int operationType, void (*callback)()) { 
    // .. determine array by system type and operation type 
    M_callbacks_r[0] = (modbus_read_t*)callback; 
} 

我刪除從callback原型參數的原因是,在標準C,空參數列表傳達沒有關於預期參數的信息(相到C++,它明確表示「無參數」)。這樣回調可以註冊而不需要演員。


正如你在評論中提到的那樣,你正在建造-Wstrict-prototypes -Werror。所以一個空的參數列表不適用於你。因此,你只限於定義registerCallback這樣的:

void registerCallback(int systemType,int operationType, void (*callback)(void)) 

注意在參數表中明確void。您需要在將該回調傳遞給registerCallback時進行回調,並將其重新投射回函數本身。

registerCallback(type, op, (void(*)(void))func_cb); 

邊注:_t後綴是在POSIX系統保留。爲了便於攜帶,最好不要用它命名你的類型。

+0

M_callbacks_r [0] =(modbus_read_t *)modbus_read_t; 不應它是 M_callbacks_r [0] =(modbus_read_t *)回調; ? – Cristian

+0

@Cristian - 是的,複製粘貼錯誤。 – StoryTeller

+0

還有什麼其他的解決方案,你會採用,而不使用typedefs? – Cristian