【问题标题】:Does dereferencing a cast to an anonymous structure pointer violate strict aliasing?取消对匿名结构指针的强制转换是否违反严格的别名?
【发布时间】:2018-09-03 10:58:57
【问题描述】:

我听说过关于 C 标准在多大程度上保证结构布局一致性的相互矛盾的事情。有限范围的争论提到了严格的别名规则。例如,比较这两个答案:https://stackoverflow.com/a/3766251/1306666https://stackoverflow.com/a/3766967/1306666

在下面的代码中,我假设在所有结构 foobarstruct { char *id; }char *id 位于同一个位置,如果它是唯一访问的成员,则可以安全地在它们之间进行转换。

不管转换是否会导致错误,它是否违反了严格的别名规则?

#include <string.h>

struct foo {
    char *id;
    int a;
};

struct bar {
    char *id;
    int x, y, z;
};

struct list {
    struct list *next;
    union {
        struct foo *foop;
        struct bar *barp;
        void *either;
    } ptr;
};

struct list *find_id(struct list *l, char *key)
{
    while (l != NULL) {
                    /* cast to anonymous struct and dereferenced */
        if (!strcmp(((struct { char *id; } *)(l->ptr.either))->id, key))
            return l;
        l = l->next;
    }
    return NULL;
}


gcc -o /dev/null -Wstrict-aliasing test.c

注意gcc 没有给出错误。

【问题讨论】:

  • “转换为匿名结构指针”中的“转换”在哪里——我确实看到了 initializationconversionvoid *struct list *)。
  • @chux ((struct { char *id; } *)(l-&gt;ptr.either))-&gt;id in find_id()
  • @chux 很难看,仔细看。
  • @chux 它采用(type) object 的形式,根据C89 标准的§3.3.4 是一个演员;见port70.net/~nsz/c/c89/c89-draft.html#3.3.4
  • @user3386109 啊,是的,我认为代码正在尝试具有相似语法的 复合文字 - 在这里不会有问题。

标签: c casting unions anonymous-struct


【解决方案1】:

是的,您的程序中存在多个与别名相关的问题。使用与底层对象的类型不匹配的匿名结构类型的左值会导致未定义的行为。它可以通过以下方式修复:

*(char**)((char *)either + offsetof(struct { ... char *id; ... }, id))

如果您知道 id 成员在所有这些中的偏移量相同(例如,它们都共享相同的前缀)。但在您的特定情况下,它是您可以做的第一个成员:

*(char**)either

因为将指向结构的指针转换为指向其第一个成员(并返回)的指针总是有效的。

另一个问题是您对联合的使用是错误的。最大的问题是它假设struct foo *struct bar *void * 都具有相同的大小和表示,这是无法保证的。此外,可以说访问除先前存储的成员之外的联合成员是未定义的,但由于缺陷报告中的解释,可以肯定地说它相当于“重新解释演员表”。但这会让你回到错误地假设相同大小/表示的问题。

您应该只删除联合,使用 void * 成员,并将 (而不是重新解释位)转换为正确的指针类型以访问指向的结构 (@987654328 @ 或 struct bar *) 或其初始 id 字段 (char *)。

【讨论】:

    猜你喜欢
    • 2016-10-09
    • 1970-01-01
    • 2012-04-02
    • 1970-01-01
    • 1970-01-01
    • 2021-07-10
    • 2020-04-11
    • 1970-01-01
    相关资源
    最近更新 更多