Я определил интерфейс:
typedef DataExchg_Status_T (*DataExchg_Iface_ReceiveDataClbk_T)(
void * p_self, uint8_t const * p_data, size_t size);
typedef struct DataExchg_Iface_Tag {
DataExchg_Status_T (*SendData)(void * p_self, uint8_t const * p_data, size_t size);
void (*RegisterReceiveDataClbk)(void * p_self,
DataExchg_Iface_ReceiveDataClbk_T receive_data_clbk,
void * p_receiver_instance);
void * pSelf;
} DataExchg_Iface_T;
, и я использую его в Object_A
.
typedef struct Object_A_Tag {
DataExchg_Iface_T * pIface;
} Object_A_T;
В Object_B
модуль
У меня есть реализация этого интерфейса:
typedef struct Object_B_Tag {
int value;
...
} Object_B_T;
DataExchg_Status_T SendData(Object_B_T * p_self, uint8_t const * p_data, size_t size) {
...
}
void RegisterReceiveDataClbk(Object_B_T * p_self,
DataExchg_Iface_ReceiveDataClbk_T receive_data_clbk,
void * p_receiver_instance) {
...
}
Все в порядке, пока я не хочу назначить вышеуказанные функциик интерфейсу в Object_A:
Object_B object_b = {...};
Object_A object_a = {
.pIface = &(DataExchg_Iface_T){
.SendData = SendData,
.RegisterReceiveDataClbk = RegisterReceiveDataClbk,
.pSelf = &object_b
}
};
Проблема в том, что я получаю предупреждение о несовместимом указателе, потому что один из параметров: void * p_self
не равен Object_B_T * p_self
в реализации интерфейса.
Есть несколько возможных решений этой проблемы:
1.Приведение к указателю на интерфейсную функцию:
SendData = (DataExchg_Status_T(*)(void *, DataExchg_Iface_ReceiveDataClbk_T, void *)SendData
Это наиболее удобное решение, но существуют убедительные доказательства того, что это решение может привести к неопределенному поведению: Приведение указателя функции к другому типу
2.Реализуйте интерфейс точно так, как объявлено, и приведите параметр в теле функции:
Это самое безопасное решение, но не самое удобное.
DataExchg_Status_T SendData(void * p_self, uint8_t const * p_data, size_t size) {
Object_B_T pSelf = p_self;
}
3.Приведение к указателю на интерфейсную функцию при инициализации интерфейса (решение 1) и приведение интерфейсной функции к реализованному типу каждый раз, когда я его использую:
Насколько мне известно, это решение не должно приводить к неопределенному поведению.
object_b.pIface->(DataExchg_Status_T(*)(Object_B *, DataExchg_Iface_ReceiveDataClbk_T, void *)SendData(...)
И, наконец, вопросы:
1) Может ли решение 1 действительно привести к неопределенному поведению в моем случае?
2) Есть лиЛюбое решение, где я могу иметь общее объявление интерфейса с указателем экземпляра Void и конкретную реализацию с указателем экземпляра Specyfic?(аналогично решению 1)