假设我有一些结构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
来获取其大小,但是您还需要对齐
答案 0 :(得分:0)
类型或变量的对齐方式是对变量可以占用的内存地址的描述-地址必须是对齐方式的 * 的倍数。但是,对于数据成员,数据成员的地址可以是任何K * alignof(S) + offsetof(S, member)
。让我们将数据成员的对齐方式定义为最大可能的整数E
,以使&some_s.member
始终是E
的倍数。
给出具有成员S
的类型member
,让A = alignof(S), O = offsetof(S, member)
。
对于某个整数S{}.member
,V = 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