You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

指向不同基类子对象的指针关系运算结果为何与标准不符?

多继承下指针转void*后的比较结果疑问
#include <iostream>

struct A{
    int a;
};
struct B{
    float b;
};
struct C:A,B{
    int c;
};

int main(){
  C* ptr = new C{};
  A* aptr = ptr;
  B* bptr = ptr;
  bool b = (void*)bptr > (void*)aptr;
  bool b2 = (void*)aptr > (void*)bptr;
  std::cout<< b<<std::endl;
  std::cout<< b2<<std::endl;
}

这段代码在GCC和Clang中运行时,输出结果为1和0,也就是(void*)bptr > (void*)aptr的结果为true,反向比较为false。但根据C++标准[expr.rel] p4的规定:

不相等的对象指针比较结果基于以下规则构成的偏序:

  • 若两个指针指向同一数组的不同元素或其子对象,下标更大的元素的指针必须更大。
  • 若两个指针指向同一对象的不同非静态数据成员或其子对象(递归地),在两者都不是零大小子对象且所属类不是 union 的前提下,声明在后的成员的指针必须更大。
  • 否则,两个指针都不要求大于对方。

从代码场景来看,aptr指向C对象的A子对象,bptr指向C对象的B子对象,这两个子对象属于同一父对象的不同基类子对象,并不符合前两条规则,因此应当适用第三条规则——即两者的大小关系没有强制要求。那为什么编译器会一致输出bptr的void*值大于aptr?


首先要明确标准中“两个指针都不要求大于对方”的含义:这并不意味着比较结果必须为false,而是表示结果是未指定(unspecified)的,编译器可以根据自身实现的内存布局返回合法的结果。

在多继承的对象模型中,编译器通常会按照基类的声明顺序来布局子对象:C对象的起始地址就是其第一个基类A的起始地址,而第二个基类B的子对象会被放置在A子对象之后的内存位置(由于A包含一个int类型成员,占4字节,B的起始地址会比A高4字节)。

当将C*转换为A*时,指针不需要调整,aptr的数值就是C对象的起始地址;而转换为B*时,指针会被调整到B子对象的起始地址(更高的内存地址)。当这两个指针被转换为void*后,它们的数值分别对应两个子对象的实际内存地址,因此比较时bptr的void*值自然大于aptr,编译器输出这样的结果完全符合其内存布局实现,并不违反标准。

内容的提问来源于stack exchange,提问作者xmh0511

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 20:31:34