C++标准中标准布局结构成员偏移的规定

huangapple go评论59阅读模式
英文:

C++ standard for member offsets of standard layout struct

问题

C++11标准是否保证,对于给定的标准布局结构,假设所有成员都有保证的大小(例如int32_t而不是int),所有编译器是否都会选择相同的内存偏移量?

也就是说,对于标准布局结构中的给定成员,C++11是否保证offsetof会在所有编译器中返回相同的值?

如果是这样的话,是否有规定该值会是多少,例如作为结构成员大小、对齐方式和顺序的函数?

【注意】这个问题涉及到C++标准的细节,可能需要详细的标准文档和专业知识才能完全理解和回答。

英文:

Does the C++11 standard guarantee that all compilers will choose the same memory offsets for all members in a given standard layout struct, assuming all members have guaranteed sizes (e.g. int32_t instead of int)?

That is, for a given member in a standard layout struct, does C++11 guarantee that offsetof will give the same value across all compilers?

If so, is there any specification of what that value would be, e.g. as a function of size, alignment, and order of the struct members?

答案1

得分: 6

以下是翻译好的部分:

  1. offsetof 不能保证在不同编译器中产生相同的值。

  2. 有关类型的最小大小有保证(例如,char >= 8 位,shortint >= 16 位,long >= 32 位,long long >= 64 位),以及大小之间的关系1sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long))。

  3. 对于大多数类型,保证对齐要求不大于类型的大小。

  4. 对于任何 struct/class,第一个(非静态2)元素必须位于 class/struct 的开头,并在没有更改可见性的情况下,顺序保证按照定义的顺序。例如:

struct { // 如果使用 `class` 也一样
    int a;
    int b;
};

由于这两者都是公共的,ab 必须按照这个顺序。但是:

struct {
    int a;
    int b;
private:
    int c;
};

第一个元素(a)必须位于结构的开头,但因为从 publicprivate 的更改,理论上编译器可以将 c 安排在 b 之前。

这个规则随着时间的推移发生了变化。在 C++98 中,即使是一个虚构的可见性说明符也允许成员的重新排列。

struct A {
    int a;
    int b;
public:
    int c;
};

public 允许重新排列 bc,尽管它们都是公共的。从那时起,规则已经收紧,所以只有具有不同可见性的元素,而在 C++ 23 中,基于可见性重新排列元素的整个概念已经消失(在我看来,早就该这样做了,我认为没有人真正使用过它,因此它一直是一条你需要了解但没有给任何人带来真正好处的规则)。


  1. 如果要变得非常技术性,要求不是在大小上,而是在范围上,因此在理论上,大小之间的关系并不完全有保证,但对于大多数实际目的来说,它是有保证的。
  2. 静态元素通常不作为类/结构对象的一部分分配。静态成员基本上分配为全局变量,但有一些关于其名称可见性的额外规则。
英文:

There is no guarantee that offsetof will yield the same values across compilers.

There are guarantees about minimum sizes of types (e.g., char >= 8 bits, short, int >= 16 bits, long >= 32 bits, long long >= 64 bits), and the relationship between sizes<sup>1</sup> (sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)).

For most types, it's guaranteed that the alignment requirement is no greater than the size of the type.

For any struct/class, the first (non-static<sup>2</sup>) element must be at the beginning of the class/struct, and in the absence of changes to the visibility, order is guaranteed to be in the order of definition. For example:

struct { // same if you use `class`
    int a;
    int b;
};

Since these are both public, a and b must be in that order. But:

struct {
    int a;
    int b;
private:
    int c;
};

The first element (a) is required to be at the beginning of the struct, but because of the change from public to private, the compiler is (theoretically) allowed to arrange c before b.

This rule has changed over time though. In C++98, even a vacuous visibility specifier allowed rearrangement of members.

struct A {
    int a;
    int b;
public:
    int c;
};

The public allows rearranging b and c even though they're both public. Since then it's been tightened up so it's only elements with differing visibility, and in C++ 23 the whole idea of rearranging elements based on visibility is gone (and long past time, in my opinion--I don't think anybody ever used it, so it's always been a rule you sort of needed to know, but did nobody any real good).


  1. If you want to get really technical, the requirement isn't really on the size, but on the range, so in theory the relationship between sizes isn't quite guaranteed, but for for most practical purposes, it is.
  2. A static element isn't normally allocated as part of the class/struct object at all. A static member is basically allocated as a global variable, but with some extra rules about visibility of its name.

答案2

得分: 1

不,没有这样的保证。C++标准明确提供了特定类型的填充和对齐要求,其中之一,这自动消除了这种保证。

可以合理地预期特定硬件平台的统一填充和对齐要求,所有在该平台上的编译器都会实现,但这也不是被保证的。

英文:

No, there are no such guarantees. The C++ standard explicitly provides for type-specific padding and alignment requirements, for one thing, and that automatically dissolves this kind of guarantee.

It might be reasonable to anticipate uniform padding and alignment requirements for a specific hardware platform, that all compilers on that platform will implement, but that again is not guaranteed.

答案3

得分: 1

绝对不是。内存布局完全由C++实现决定。唯一的例外,只适用于标准布局类,即第一个非静态数据成员或基类子对象具有零偏移量。还有一些其他约束,例如子对象的大小和对齐方式以及子对象地址排序的约束,但没有任何确定子对象具体偏移量的内容。

然而,通常编译器会遵循某种ABI规范,以适应特定的体系结构/平台,因此相同体系结构/平台上的编译器可能会使用相同的ABI和相同的内存布局(例如,在Linux x86-64上,GCC和Clang至少会使用SysV x86-64 ABI以及Itanium C++ ABI)。

英文:

Absolutely not. Memory layout is completely up to the C++ implementation. The only exception, only for standard-layout classes, is that the first non-static data member or base class subobject(s) have zero offset. There are also some other constraints, e.g. due to sizes and alignment of subobjects and constraints on ordering of addresses of subobjects, but nothing that determines concrete offsets of subobjects.

However, typically compilers follow some ABI specification on any given architecture/platform, so that compilers for the same architecture/platform will likely use the same ABI and same memory layout (e.g. the SysV x86-64 ABI together with the Itanium C++ ABI on Linux x86-64 at least for both GCC and Clang).

huangapple
  • 本文由 发表于 2023年2月6日 03:57:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/75355103.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定