是否有符合标准的方法来确定非静态成员的对齐方式?

时间:2019-07-03 00:41:30

标签: c++ language-lawyer typetraits

假设我有一些结构S和一个非静态成员member,如本例所示:

struct S { alignas(alignof(void *)) char member[sizeof(void *)]; };

如何获得member的对齐方式?

运算符alignof仅适用于完整类型,不适用于表达式[in 7.6.2.5.1],尽管GCC允许,所以alignof(S::member)和Clang支持它。

在没有此限制的情况下,“以语言为依据”的标准方式是什么?

此外,sizeof允许使用表达式自变量,是否存在不对称的原因?

实际需要考虑的是能够获得模板结构的成员的对齐方式,您可以decltype来获取其类型,sizeof来获取其大小,但是您还需要对齐

1 个答案:

答案 0 :(得分:0)

类型或变量的对齐方式是对变量可以占用的内存地址的描述-地址必须是对齐方式的 * 的倍数。但是,对于数据成员,数据成员的地址可以是任何K * alignof(S) + offsetof(S, member)。让我们将数据成员的对齐方式定义为最大可能的整数E,以使&some_s.member始终是E的倍数。

给出具有成员S的类型member,让A = alignof(S), O = offsetof(S, member)
对于某个整数S{}.memberV = K * A + O的有效地址是K
V = K * A + O = gcd(A, O) * (K * A / gcd(A, O) + O / gcd(A, O))
对于K = 1,不存在其他因素。
因此,gcd(A, O)是对未知K有效的最佳因子。

换句话说,"alignof(S.member)" == gcd(alignof(S), offsetof(S, member))

请注意,此对齐方式始终是2的幂,因为alignof(S)始终是2的幂。

*:在我对标准的简短介绍中,我找不到这种保证,这意味着变量的地址可以K * alignment + some_integer。但是,这不会影响最终结果。


我们可以定义一个宏来计算数据成员的对齐方式:

#include <cstddef> // for offsetof(...)
#include <numeric> // for std::gcd

// Must be a macro, as `offsetof` is a macro because the member name must be known
// at preprocessing time.
#define ALIGNOF_MEMBER(cls, member) (::std::gcd(alignof(cls), offsetof(cls, member)))

这仅保证对标准布局类型(如offsetof is only guaranteed valid for standard layout types)有效。如果该类不是标准布局,则有条件地支持此操作。

示例:

#include <cstddef>
#include <numeric>

struct S1 { char foo; alignas(alignof(void *)) char member[sizeof(void *)]; };
struct S2 { char foo; char member[sizeof(void *)]; };

#define ALIGNOF_MEMBER(cls, member) (::std::gcd(alignof(cls), offsetof(cls, member)))

int f1() { return ALIGNOF_MEMBER(S1, member); } // returns alignof(void *) == 8
int f2() { return ALIGNOF_MEMBER(S1, foo); }    // returns 8*
int f3() { return ALIGNOF_MEMBER(S2, member); } // returns 1

// *: alignof(S1) == 8, so the `foo` member must always be at an alignment of 8

Compiler Explorer