幻像类型与原始类型具有相同的对齐方式吗?

Zet*_*eta 26 c++ struct types memory-alignment language-lawyer

请考虑以下包含一些环境值的结构:

struct environment_values {
  uint16_t humidity;
  uint16_t temperature;
  uint16_t charging;
};
Run Code Online (Sandbox Code Playgroud)

我想为这些带有幻像类型*的值添加一些额外的信息,并同时使它们的类型不同:

template <typename T, typename P>
struct Tagged {
    T value;
};

// Actual implementation will contain some more features
struct Celsius{};
struct Power{};
struct Percent{};

struct Environment {
  Tagged<uint16_t,Percent> humidity;
  Tagged<uint16_t,Celsius> temperature;
  Tagged<uint16_t,Power>   charging;
};
Run Code Online (Sandbox Code Playgroud)

内存布局是Environment一样的environment_values吗?这是否也适用于混合类型布局,例如:

struct foo {
    uint16_t value1;
    uint8_t  value2;
    uint64_t value3;
}

struct Foo {
    Tagged<uint16_t, Foo>  Value1;
    Tagged<uint8_t , Bar>  Value2;
    Tagged<uint64_t, Quux> Value3;
}
Run Code Online (Sandbox Code Playgroud)

对于我迄今为止尝试过的所有类型,以下断言都是:

template <typename T, typename P = int>
constexpr void check() {
    static_assert(alignof(T) == alignof(Tagged<T,P>), "alignment differs");
    static_assert(sizeof(T)  == sizeof(Tagged<T,P>),  "size differs");
}

// check<uint16_t>(), check<uint32_t>(), check<char>() …
Run Code Online (Sandbox Code Playgroud)

由于标记和未标记变体的大小也相同,我答案应该是肯定的,但我想有一定的确定性.

*我不知道如何在C++中调用这些标记值."强类型typedef"?我从Haskell取名.

gsa*_*ras 10

标准在[basic.align]/1中提到:

对象类型具有对齐要求(3.9.1,3.9.2),这些要求对可以分配该类型的对象的地址施加限制.对齐是实现定义的整数值, 表示可以分配给定对象的连续地址之间的字节数.对象类型对该类型的每个对象强制对齐要求; 可以使用对齐说明符(7.6.2)请求更严格的对齐.

而且,[basic.compound]/3,提到:

指针类型的值表示是实现定义的.布局兼容类型的指针应具有相同的值表示和对齐要求(6.11).[注意:过度对齐类型(6.11)的指针没有特殊表示,但它们的有效值范围受扩展对齐要求的限制].

因此,可以保证布局兼容类型具有相同的对齐方式.

struct { T m; }并且T不是布局兼容的.

正如指出这里,为了让两个元素是布局兼容的,则它们都必须是标准布局类型,它们的非静态数据成员必须具有相同类型和相同的顺序出现.

struct { T m; }只包含一个T,但是它T是一个T所以它不能包含一个T作为其第一个非静态数据成员.

  • `struct {T m; }`和`T`不是布局兼容的.为了与布局兼容,它们都必须是标准布局类型,并且它们的非静态数据成员必须以相同的类型和相同的顺序出现.`T`可能不是标准布局.`T`甚至可能不是一个班级.但即使`T`确实满足这些要求,`struct {T m; ``只包含一个`T`,但`T`是一个`T`,所以它不能包含`T`作为它的第一个非静态数据成员. (2认同)

Tri*_*dle 7

根据法律规定,类型的大小和排列是实现定义的,如果有任何关于什么sizeofalignof将返回的保证,标准会给你很少.

template <typename T, typename P>
struct Tagged {
    T value;
};
Run Code Online (Sandbox Code Playgroud)

从理论上讲,允许编译器在此结构的末尾添加填充,这显然会改变大小,也可能改变对齐.在实践中,我唯一可以设想这种情况发生的情况是,如果T给出某种特定于编译器的"打包"属性,但Tagged不是(但即便如此,GCC似乎也可以正常工作).

在任何情况下,我都会说添加一些静态断言以确保编译器是合理的是一个好主意 - 这正是你所做的:).