【问题标题】:Ensuring field alignment in struct确保结构中的字段对齐
【发布时间】:2021-11-16 04:22:33
【问题描述】:

我正在为一种语言设计抽象语法树 (AST)。我的词法标记看起来像

typedef struct {
    tokenHeader header;
    tokenData data;
} lexicalToken;

其中tokenHeadertokenDatastructs。至于我的 AST 节点,我有一个基本类型:

#define AST_HEADER \
    struct astNode *parent; \
    tokenHeader header;

typedef struct astNode {
    AST_HEADER
} astNode;

以及一些拆分类型。例如,

typedef struct {
    AST_HEADER
    astNode *nodes[2];
} astTwoSplitNode;

我之所以在AST_HEADER 中不包含tokenData 是因为几乎所有令牌都不使用该字段。这让我想到

typedef struct {
    astNode *parent;
    lexicalToken token;
    // Nodes which use tokenData are always terminal nodes.
} astNodeWithData;

这终于让我想到了我的问题:astNodeWithData 的排列方式是否保证我可以将astNodeWithData* 转换为astNode*,引用header 字段,并在预期的方式?

如果没有,有没有办法指示我的编译器(gcc,如果有帮助)强制执行这样的安排?

【问题讨论】:

  • “我可以将 astNodeWithData* 转换为 astNode* 的这种方式,”最好避免。寻找不涉及 cast 的解决方案。 (struct/unionstruct 等)
  • 即使你使用 union 或 memcpy,也不要忘记打包结构
  • @chux-ReinstateMonica,为什么要避免这种情况?这不就是struct sockaddr*之类的东西吗?
  • struct sockaddr* 用于 C 的受控子集(例如 *nix),而不是在 C 的广阔世界中。代码可以对第一个成员(如果是通用类型)使用强制转换技巧,但是除此之外,便携性被牺牲了,UB 隐约可见。施法技巧也击败了类型检查。 IMO,两者都没有必要。

标签: c struct alignment


【解决方案1】:

您实际上可以做的是将astNodeWithData * 转换为astNode **,而不是astNode *,因为结构的地址与第一个成员的地址相同。

C standard 第 6.7.2.1p15 节关于“结构和联合说明符”的状态:

在结构对象中,非位域成员和 位域所在的单元的地址增加 声明它们的顺序。 指向结构的指针 适当转换的对象指向其初始成员(或 如果该成员是位域,则到它所在的单元 驻留),反之亦然。 结构对象,但不是在其开头

所以以下是允许的:

astNodeWithData dataNode;
// populate dataNode
astNode **nodePtr = (astNode **)&dataNode;
// access (*nodePtr)->header
astNodeWithData *dataNodePtr = (astNodeWithData *)nodePtr;
// access dataNodePtr->token

【讨论】:

  • 但是dataNodePtr->token 是否可以保证与(*nodePtr)->header 具有相同的偏移量?
  • @DanielWalker 他们几乎肯定会不会astNodeWithData 的第一个成员是parent,即astNode *,因此astNode 对象存储在其他位置。 astNodeWithData 的第二个成员是 token,即 lexicalToken,其中 1) 与指针 parent 不同,2) 似乎与 parent 指向的内容没有任何共同之处。
  • 啊,对不起。我没有正确地表达这个问题。我真正想知道的是offsetof(astNode, header)是否保证等于offsetof(astNodeWithData, token)
  • @DanielWalker 取决于tokenHeader, lexicalToken的类型。
  • 明白了。所以,看起来我可以做#define AST_HEADER struct { struct astNode *parent; lexicalHeader header;};,然后在我的astNodeWithData 中添加一个额外的lexicalData data;
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-21
  • 2021-11-16
  • 2014-12-01
  • 1970-01-01
  • 2019-12-13
相关资源
最近更新 更多