是否比较两个 void 指针到 C++ 中定义的不同对象?

发布于 2024-12-17 12:58:03 字数 618 浏览 2 评论 0原文

受到关于动态转换为 void*这个答案的启发:

<前><代码>... 布尔 eqdc(B* b1, B *b2) { 返回dynamic_cast(b1)==dynamic_cast(b2); } ... int main() { DD *dd = 新的 DD(); D1 *d1 =dynamic_cast(dd); D2*d2=dynamic_cast(dd); ... eqdc(d1, d2) ...

我想知道比较两个指向有效的空指针是否相等是否是C++中完全定义的行为(根据03或11标准),但是不同的对象

更一般地说,但可能不那么相关,比较(==!=)始终定义的 void* 类型的两个值,或者是它要求它们持有指向有效对象/内存区域的指针?

Inspired by this answer about dynamic cast to void*:

...
bool eqdc(B* b1, B *b2) {
    return dynamic_cast<void*>(b1) == dynamic_cast<void*>(b2);
}
...
int main() {
    DD *dd = new DD();
    D1 *d1 = dynamic_cast<D1*>(dd);
    D2 *d2 = dynamic_cast<D2*>(dd);
    ... eqdc(d1, d2) ...

I am wondering if it is fully defined behaviour in C++ (according to the 03 or 11 standard) to compare two void pointers for (in)equality that point to valid, but different objects.

More generally, but possibly not as relevant, is comparing (==or !=) two values of type void* always defined, or is it required that they hold a pointer to a valid object/memory area?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

厌味 2024-12-24 12:58:03

C 说:

两个指针比较相等当且仅当两者都是空指针,并且都是指向
相同的对象(包括指向对象的指针和其开头的子对象)或函数,
两者都是指向同一数组对象最后一个元素之后的指针,或者一个是指针
一个指向一个数组对象的末尾,另一个是指向另一个数组对象的开头的指针
恰好紧随地址中第一个数组对象的数组对象
空间。

C++ 说:

如果两个相同类型的指针比较相等
并且只有当它们都为空、都指向相同的函数或者都代表相同的地址时。

因此,这意味着:

a)

它是 C++ 中完全定义的行为(根据 03 或 11 标准),用于比较两个指向有效但不同对象的 void 指针是否相等。

所以是的,在 C 和 C++ 中都是如此。您可以比较它们,在这种情况下,当它们指向同一对象时,它们将比较为 true。这很简单。

b)

是否比较(==或!=)始终定义的 void* 类型的两个值,或者是否要求它们保存指向有效对象/内存区域的指针?

同样,比较是明确定义的(标准说“当且仅当”,因此两个指针的每次比较都是明确定义的)。但是...

  • C++ 用“地址”来讨论,所以我认为这意味着标准要求它“按照我们的预期”工作,
  • 但是,C 要求两个指针要么为空,要么指向对象或函数,或者数组对象后面的一个元素。如果我的阅读能力没有下降,这意味着如果在给定的平台上你有两个具有相同值的指针,但没有指向有效的对象(例如未对齐),则比较它们应该是明确定义的并产生错误。

这太令人惊讶了!

事实上,这不是 GCC 的工作方式:

int main() {
    void* a = (void*)1; // misaligned, can't point to a valid object
    void* b = a;
    printf((a == b) ? "equal" : "not equal");
    return 0;
}

结果:

equal

也许 C 中的 UB 拥有一个不是空指针的指针并且不指向一个对象、子对象或数组中最后一个对象之后的对象?嗯...这是我的猜测,但我们有:

整数可以转换为任何指针类型。除先前指定的情况外,
结果是实现定义的,可能未正确对齐,可能不指向
引用类型的实体,并且可能是陷阱表示。

所以我只能解释为上面的程序定义良好,C标准期望它打印“不等于”,而GCC并没有真正遵守标准,但给出了更直观的结果。

C says:

Two pointers compare equal if and only if both are null pointers, both are pointers to the
same object (including a pointer to an object and a subobject at its beginning) or function,
both are pointers to one past the last element of the same array object, or one is a pointer
to one past the end of one array object and the other is a pointer to the start of a different
array object that happens to immediately follow the first array object in the address
space.

C++ says:

Two pointers of the same type compare equal if
and only if they are both null, both point to the same function, or both represent the same address.

Hence it would mean that:

a)

it is fully defined behaviour in C++ (according to the 03 or 11 standard) to compare two void pointers for (in)equality that point to valid, but different objects.

So yes, in both C and C++. You can compare them and in this case they shall compare as true iff they point to the same object. That's simple.

b)

is comparing (==or !=) two values of type void* always defined, or is it required that they hold a pointer to a valid object/memory area?

Again, the comparison is well-defined (standard says "if and only if" so every comparison of two pointers is well-defined). But then...

  • C++ talks in terms of "address", so I think this means that the standard requires this to work "as we'd expect",
  • C, however, requires both the pointers to be either null, or point to an object or function, or one element past an array object. This, if my reading skills aren't off, means that if on a given platform you have two pointers with the same value, but not pointing to a valid object (e.g. misaligned), comparing them shall be well-defined and yield false.

This is surprising!

Indeed that's not how GCC works:

int main() {
    void* a = (void*)1; // misaligned, can't point to a valid object
    void* b = a;
    printf((a == b) ? "equal" : "not equal");
    return 0;
}

result:

equal

Maybe it's UB in C to have a pointer which isn't a null pointer and doesn't point to an object, subobject or one past the last object in an array? Hm... This was my guess, but then we have that:

An integer may be converted to anypointer type. Except as previously specified, the
result is implementation-defined, might not be correctly aligned, might not point to an
entity of the referenced type, and might be a trap representation.

So I can only interpret it that the above program is well-defined and the C standard expects it to print "not equal", while GCC doesn't really obey the standard but gives a more intuitive result.

帝王念 2024-12-24 12:58:03

C++11、5.10/1:

可以比较相同类型的指针(指针转换后)
为了平等。相同类型的两个指针比较相等当且仅
如果它们都为空,则都指向同一个函数,或者两者都指向
代表同一个地址

所以是的,具体比较就可以了。

一般来说,尝试创建不是有效地址的指针值是未定义的行为 - 例如使用指针算术在数组的开头之前或末尾之后 - 更不用说使用它们了。像 (void*)23 这样的结果是实现定义的,因此除非实现具有特定权限,否则比较这些内容实际上也是未定义的行为,因为实现可能会定义结果是void* 的陷阱值。

C++11, 5.10/1:

Pointers of the same type (after pointer conversions) can be compared
for equality. Two pointers of the same type compare equal if and only
if they are both null, both point to the same function, or both
represent the same address

So yes, the specific comparison is OK.

In general it is undefined behavior to attempt to create a pointer value that isn't a valid address - for example using pointer arithmetic to go before the beginning or after the one-after-the-end of an array - let alone use them. The result of stuff like (void*)23 is implementation-defined, so barring specific permission from the implementation it is in effect undefined behavior to compare those too, since the implementation might define that the result is a trap value of void*.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文