c++ - 是否有符合标准的方法来确定非静态成员的对齐方式?
问题描述
假设我有一些结构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
获取它们的大小,但是您还需要对齐方式。
解决方案
类型或变量的对齐是对变量可以驻留的内存地址的描述——地址必须是对齐*的倍数。但是,对于数据成员,数据成员的地址可以是任何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)
是对 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
推荐阅读
- python - 由于文件不存在,命令“jupyter lab”不起作用
- java - Java 垃圾收集的确切功能
- html - 为什么这个动画会移到右下角?
- java - Java中基于文本的扫雷克隆中的空格扩展
- apache-kafka - Kafka生产者确认时间延迟和调试
- java - 尝试连接到 HBase 时出现 java.lang.NumberFormatException
- r - 如何在除法操作周围静默撤消 dplyr 变异
- php - 查找所有带有“[string]”的字符,并将其变成一个数据数组
- c - 在 c 中处理字符串 - 扩展、替换、存储和打印字符串
- .net - 我无法从 VB.NET 连接到 SQL Server