这两个C函数调用有什么区别?

4

我正在以两种方式调用以下库函数:

unsigned int
LsSendToQ(unsigned int p4Node, const char queueName[4], lsMsg *pMsg,
          unsigned int prio) {

}

第一种方法:
LsSendToQ((unsigned int)0, (const char *)Q_NAME, (lsMsg *)(void *)pMsg, 0) 

第二种方式如下:
LsSendToQ((unsigned int)0, (const char *)Q_NAME, (lsMsg *)pMsg, 0) 

这两个调用都可以通过编译,但哪一个是正确的呢?为什么第一个调用中使用了(void *),看起来像是一个函数指针呢?


https://dev59.com/nmgu5IYBdhLWcg3wDSwG - Tharif
2
Q_NAME 是如何定义的?pMsg 是如何定义的?第一个转换是无用的,(lsMsg *)(void *)pMsg 是多余的,但可能需要消除编译器警告。 - chqrlie
2
你应该避免冗余的强制类型转换;尝试使用 LsSendToQ(0, Q_NAME, pMsg, prio);。对于 pMsg 的强制类型转换可能是必需的,但仅根据您发布的内容无法确定。 - M.M
顺便提一下,虽然在 C 中第一个只是噪音,但我可以想象在 C++ 的某些多重继承情况下会有所不同。 (从和到 void* 的转换将始终是 reinterpret_cast,而直接转换可能会被翻译为静态转换到子对象的地址)。 - Peter - Reinstate Monica
3个回答

3
指向 void 的指针是一种“通用”指针类型。 void * 可以在没有显式转换的情况下转换为任何其他指针类型。您不能对 void * 进行解引用或进行指针算术运算;您必须先将其转换为指向完整数据类型的指针。请参见此 answer
因此,参数 pMsg 不直接与 lsMsg * 兼容,然后第二次调用是使用函数调用中的一种可能方式[我没有测试它]。
顺便说一句,只要 pMsg 的类型是 lsMsg *,第一个就足够了。
编辑:
第二个足以覆盖第一个。

https://dev59.com/nmgu5IYBdhLWcg3wDSwG#11629682 - user694733
感谢提供信息。 - Shafi
嗯,“void *可以在没有显式转换的情况下转换为任何其他指针类型。”:这是否意味着OP可以省略最后一个(lsMsg *)(void *)pMsg中的lsMsg *强制转换(因为参数传递是一种初始化形式)?“您无法引用void *”:与OP的问题无关。“因此,参数pMsg不能直接兼容lsMsg *,那么第二个调用是使用函数调用的可能方式”:是的,但第一个也是。所以呢?“顺便说一句,只要pMsg的类型是lsMsg *,第一个就足够了。”当然;不需要强制转换 - Peter - Reinstate Monica

3
第二个版本是正确的。
第一个调用看起来像是试图规避不兼容类型警告。如果pMsg与lsMsg *不兼容,则可以通过在两者之间进行void*转换来消除编译器警告。
然而,你不应该这样做,因为它几乎肯定会隐藏程序中的错误!要么两个指针类型完全不兼容,在这种情况下,访问指针可能会导致程序立即崩溃;要么它们在理论上是兼容的,但编译器实现了类型别名,(void*)转换将隐藏违反“严格别名规则”的行为。在任何一种情况下,你都有未定义的行为和严重的错误。

2
我认为第一种方式将指针类型转换两次是没有必要的。使用第二种方式就足够了。

我猜这是一种消除编译器警告有关潜在不安全转换的方法。 - John Hascall

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接