UB 是不是将 void 指针与 C 中的类型化指针进行比较(是不是相等)?

Posted

技术标签:

【中文标题】UB 是不是将 void 指针与 C 中的类型化指针进行比较(是不是相等)?【英文标题】:Is it UB to compare (for equality) a void pointer with a typed pointer in C?UB 是否将 void 指针与 C 中的类型化指针进行比较(是否相等)? 【发布时间】:2020-11-19 06:09:59 【问题描述】:

我有一个类型化的指针typed,它是使用指针算法初始化的,以指向数组中的一个对象。我还有一个函数,它接受两个指针参数,第一个类型与上述指针相同,第二个是void *(请参阅下面代码中的myfunc())。

如果我将typed 作为第一个参数传递,另一个与typed 类型相同的指针作为第二个参数传递,然后在函数内比较它们是否相等,这是未定义的行为吗?

#include <stdio.h>

typedef struct S int i; float f; s;

void myfunc(s * a, void * b)

  if (a == b)  // <-------------------------------- is this UB?
    printf("the same\n");


int main()

  s myarray[] = 7, 7.0, 3, 3.0;
  s * typed = myarray + 1;
  myfunc(typed, &(myarray[0]));

  return 0;


更新:好的,所以我在上面发布我的问题后一天回来,有两个很好的答案(感谢@SouravGhosh 和@dbush)。一个比另一个早了不到一分钟(!),但从第一个 cmets 的外观来看,答案最初是错误的,只有在第二个答案发布后才更正。我接受哪一个?在这种情况下,是否有一种协议可以接受一个答案而不是另一个答案?

【问题讨论】:

【参考方案1】:

不,这不是未定义的行为。这是在等式运算符约束的规范中允许并明确定义的。引用C11,第 6.5.9 章

一个操作数是一个指向对象类型的指针,另一个是一个指向限定或非限定版本的 void 的指针;

来自同一章的第 5 段

[...] 如果一个操作数是指向对象类型的指针,而另一个是指向 void 的限定或非限定版本的指针,则前者将转换为后者的类型。

【讨论】:

抱歉 Sourav:在没有任何关于我应该如何在你和 dbush 之间的“平局”中统治的反馈的情况下,我掷硬币并且 dbush 赢了。不过答案很好。【参考方案2】:

这种比较定义明确。

当通过==void * 与另一个指针类型进行比较时,另一个指针将转换为void *

此外,C standard 的第 6.5.9p6 节对与 == 的指针比较进行了以下说明:

当且仅当两个指针都是空指针时,两个指针比较相等 是指向同一对象的指针(包括指向对象的指针和 开头的子对象)或函数,两者都是指向一个的指针 超过同一个数组对象的最后一个元素,或者一个是指向 一个超过一个数组对象的末尾,另一个是指向 立即发生的不同数组对象的开始 跟随地址空间中的第一个数组对象。

这里没有提到未定义的行为。

【讨论】:

void * operand is converted to the type of the other operand.... 6.5.9p5? @SouravGhosh 啊,我倒过来了。固定。 不用担心,它适用于空指针常量,不适用于void*s。 请注意,在 clang 和 gcc 中,最后一种比较描述的是,“一个是指向一个数组对象末尾的指针,另一个是指向不同数组对象开头的指针恰好紧跟在地址空间中的第一个数组对象之后”可能会导致行为不仅与产生 1 的比较不一致,而且与产生未指定值的比较不一致。 @supercat I posted a question(你也回答了)关于这个话题。

以上是关于UB 是不是将 void 指针与 C 中的类型化指针进行比较(是不是相等)?的主要内容,如果未能解决你的问题,请参考以下文章

嵌入式进阶必看!7个硬核的 C 语言要点

void类型及void指针

C 语言数据类型本质 ( void 关键字作用 | 数据类型封装 | 作为 参数 或 返回值 代表无 | void* 指针赋值与被赋值 | void 类型变量不存在 )

C++。错误:void 不是指向对象的指针类型

关于void*类型的用法(相当于OC中的id类型)

通过 void 指针通过 C ABI 传递 C++ 对象(可能具有多重虚拟继承)