首页 > 解决方案 > 是否有符合标准的方法来确定非静态成员的对齐方式?

问题描述

假设我有一些结构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获取它们的大小,但是您还需要对齐方式。

标签: c++language-lawyertypetraits

解决方案


类型或变量的对齐是对变量可以驻留的内存地址的描述——地址必须是对齐*的倍数。但是,对于数据成员,数据成员的地址可以是任何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)是对 unknown 有效的最佳因子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仅保证对标准布局类型有效。如果类不是标准布局,则有条件地支持此操作。

例子:

#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

编译器资源管理器


推荐阅读