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

时间:2011-11-22 10:43:59

标签: c++ comparison void-pointers language-lawyer

受到this answer的启发,关于动态广告投放到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) ...

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

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

2 个答案:

答案 0 :(得分:11)

C说:

  

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

C ++说:

  

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

因此意味着:

A)

  

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

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

b)中

  

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

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

  • C ++谈论“地址”,所以我认为这意味着标准要求它“按照我们的预期”工作,
  • 但是,
  • C要求指针既可以为null,也可以指向对象或函数,或指向数组对象之后的一个元素。如果我的阅读技巧没有关闭,这意味着如果在给定的平台上你有两个具有相同值的指针,但没有指向有效的对象(例如未对齐),那么比较它们应该是明确的并且产生错误。

这太令人惊讶了!

确实是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;
}

结果:

equal

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

  

整数可以转换为anypointer类型。除了之前的具体说明,   结果是实现定义,可能没有正确对齐,可能不指向   引用类型的实体,可能是陷阱表示。

所以我只能解释它上面的程序定义明确,C标准期望它打印“不相等”,而GCC并没有真正服从标准,而是提供更直观的结果。

答案 1 :(得分:3)

C ++ 11,5.10 / 1:

  

可以比较相同类型的指针(指针转换后)   为了平等。相同类型的两个指针比较等于if和only   如果它们都为null,则指向相同的函数,或两者都指向   代表相同的地址

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

一般来说,尝试创建一个非有效地址的指针值是未定义的行为 - 例如使用指针算法在数组的开头之前或之后进行 - 更不用说了使用它们。像(void*)23之类的东西的结果是实现定义的,因此除了实现的特定权限之外,它实际上也是未定义的行为来比较它们,因为实现可能会定义结果是陷阱值{{1} }。