【问题标题】:Function pointer casting or parameters casting when using interface使用接口时的函数指针转换或参数转换
【发布时间】:2019-06-20 20:47:46
【问题描述】:

我已经定义了接口:

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

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

2。完全按照声明实现接口并在函数体中转换参数:

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

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

3.初始化接口时转换为接口函数指针(方案一),每次使用时都将接口函数转换为它的实现类型:

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

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

最后是问题:

1) 在我的情况下,解决方案 1 真的会导致未定义的行为吗?

2) 有什么解决方案可以让我使用 void 实例指针进行通用接口声明,并使用特定实例指针进行特定实现? (类似于方案一)

【问题讨论】:

    标签: c casting function-pointers


    【解决方案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 回调函数的常见习语。

    【讨论】:

      猜你喜欢
      • 2019-04-13
      • 1970-01-01
      • 2015-11-03
      • 1970-01-01
      • 2021-05-09
      • 2013-03-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多