gpt4 book ai didi

c - 使用接口(interface)时函数指针转换或参数转换

转载 作者:行者123 更新时间:2023-11-30 19:26:44 25 4
gpt4 key购买 nike

我已经定义了接口(interface):

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模块中

<小时/>

我已经实现了这个接口(interface):

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中的接口(interface):

Object_B object_b = {...};

Object_A object_a = {
.pIface = &(DataExchg_Iface_T){
.SendData = SendData,
.RegisterReceiveDataClbk = RegisterReceiveDataClbk,
.pSelf = &object_b
}
};

问题是我收到不兼容的指针警告,因为接口(interface)实现中的参数之一:void * p_self 不等于Object_B_T * p_self

此问题有一些可能的解决方案:

<强>1。转换为接口(interface)函数指针:

SendData = (DataExchg_Status_T(*)(void *, DataExchg_Iface_ReceiveDataClbk_T, void *)SendData

这是最方便的解决方案,但有一些强有力的证据表明该解决方案可能会导致未定义的行为:Casting a function pointer to another type

<强>2。完全按照声明的方式实现接口(interface)并在函数体中强制转换参数:

这是最安全的解决方案,但不是最方便的。

DataExchg_Status_T SendData(void * p_self, uint8_t const * p_data, size_t size) {
Object_B_T pSelf = p_self;
}

<强>3。初始化接口(interface)时强制转换为接口(interface)函数指针(方案1),每次使用时将接口(interface)函数强制转换为其实现类型:

据我所知,此解决方案不应导致未定义的行为。

object_b.pIface->(DataExchg_Status_T(*)(Object_B *, DataExchg_Iface_ReceiveDataClbk_T, void *)SendData(...)

最后一个问题:

1) 在我的例子中,解决方案 1 真的会导致未定义的行为吗?

2)是否有任何解决方案可以让我使用 void 实例指针进行通用接口(interface)声明,并使用特定实例指针进行特定实现? (与方案1类似)

最佳答案

第二个选项,更改函数定义以匹配指针类型并将 void * 转换为正确的类型,这是实现此类回调的正确且首选的方法。

作为示例,请查看 man page for qsort 。该函数的声明如下:

   void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));

它给出了回调函数的示例:

static int
cmpstringp(const void *p1, const void *p2)
{
/* The actual arguments to this function are "pointers to
pointers to char", but strcmp(3) arguments are "pointers
to char", hence the following cast plus dereference */

return strcmp(* (char * const *) p1, * (char * const *) p2);
}

如您所见,此示例将 void * 转换为正确的类型以便使用它。这是 C 回调函数的常见习惯用法。

关于c - 使用接口(interface)时函数指针转换或参数转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56693665/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com