成员都是位标志的相同大小的2类之间的实际差异

时间:2018-12-21 01:05:31

标签: c++

通常,在C ++中,类的大小是其成员(包括任何基类成员)的总大小。

像这样定义的两个类之间的实际区别是什么?它们的成员都代表位标志:

class A { // 16 bytes
    uint64_t x;
    uint64_t y;
};

class B { // 16 bytes
    uint64_t x;
    uint32_t y;
    uint16_t z;
    uint8_t  r;
    uint8_t  s;
};

我能想到的是:

  • B的数据可以更精细地访问,而无需执行按位运算。例如,要访问A中的B :: r等价物,您必须执行以下操作:

    (a.y & 0xFF00) >> 8; // b.r
    
  • 在语义上,不同的成员意味着这些成员的数据属于该类的不同概念。即:“年龄”与“长度”是一个不同的概念。

我认为这两个课程都相同:

  • 内存布局。

我不知道的事情:

  • 两个类之间如何影响CPU缓存。
  • 在这两个类的成员上执行按位运算时,任何速度差。

1 个答案:

答案 0 :(得分:2)

问题的答案在很大程度上取决于目标平台,尤其是其应用程序二进制接口(ABI)。您可以在此处检查X86-64 System V ABI(Windows具有不同的ABI):

https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI

ABI控制结构布局(除其他事项外),正如Sam所提到的,两个结构的布局不能保证相同。对于X86-64,它们恰好是相同的,但是对于其他一些目标,可以在字段之间引入填充。

如何访问字段本身也取决于目标体系结构,即可用于执行加载和存储的指令。存在许多不直接支持字节大小的内存访问的机器,因此在更大的负载之后,将通过位移位来访问字段r和s。为现场访问操作生成正确的代码是编译器的责任。

也可以想象,某些机器可能具有足够宽的寄存器来容纳整个结构,这意味着访问任何字段都需要花些时间。确实,X86-64 ABI指定了函数调用语义,该函数会将两个寄存器中的任何一个结构传递给被调用者,后者将需要提取数据,可能将其压入堆栈以在函数中进行访问。

对于几乎所有现实应用程序而言,这些细节都无关紧要,并且任何一种结构布局都可以正常工作。从程序员的角度来看,假设字段与程序中的逻辑概念相对应,则第二种方法是更可取的。读取简单的字段访问要比移位和字段访问掩码容易得多。

当然,某些应用程序非常关心布局,性能,空间问题或系统之间的互操作性。