【问题标题】:GCC forward declarations and __may__aliasGCC 前向声明和 __may__alias
【发布时间】:2010-10-05 19:30:23
【问题描述】:

我正在尝试转发声明具有 _可能_alias 属性的类,但是当我尝试这样做时 GCC 会出错:

struct __attribute__((__may_alias__)) MyType;
MyType* foo();

typedef struct  __attribute__((__may_alias__)) MyType { ... } MyType;
MyType* foo() {}

给出错误: testc.c:4:错误:重新定义 typedef ‘A’
testc.c:1:注意:以前的“A”声明在这里
testc.c:5:错误:“foo”的类型冲突
testc.c:2:注意:之前的“foo”声明在这里

有没有办法做到这一点?

【问题讨论】:

    标签: c gcc


    【解决方案1】:

    C 不允许两次执行typedef。此外,您必须区分structtypedef 的前向声明。最简单的方法是使用与struct 标记和typedef 标识符相同的标记。没有属性的东西,在标准 C 中,这看起来像:

    /* this is a forward declaration of struct and typedef */
    typedef struct MyType MyType;
    MyType* foo(void);
    
    /* declare the struct as a struct */
    struct MyType { };
    MyType* foo(void) { return NULL; }
    

    现在有了属性。您必须找出它适用于struct 声明或typedef。我的猜测是struct,但快速查看 gcc 信息应该会告诉你。

    /* this is a forward declaration of struct and typedef */
    typedef __attribute__((__may_alias__)) struct MyType MyType;
    
    /* declare the struct as a struct */
    __attribute__((__may_alias__)) struct MyType { };
    

    【讨论】:

    • 对不起,我修复了我的代码以具有正确的属性,而不是用于生成它的宏。这可能会让您感到困惑。
    • 答案似乎是错误的(在 GCC 5.4.0 上测试)。作为类型属性,__attribute__((__may_alias__)) 必须在struct} 之后添加。在struct之前添加没有效果,锯齿问题依然存在。
    • @ThomasLee,这个答案已经快 8 岁了。不知道当时是否正确,是否同时发生了变化,或者即使问题仍然相关。这是编译器扩展的缺点之一。
    【解决方案2】:

    经过几个小时的实验,这似乎是 GCC 的一个限制错误。较新的 GCC 没有这个问题。

    1。前向声明,没有may_alias(错误行为)

    下面是严格别名问题的最小演示:

    #include <stdio.h>
    
    struct MyType;  // Forward declaration here, without may_alias.
    
    void foo(struct MyType *, int *b);
    
    struct MyType {
        short a;
    };  // Full definition here, without may_alias.
    
    void f(struct MyType *my_type, int *b)
    {
        *b = 1;
        my_type->a = 0;
    
        if (*b == 1) {
            printf("Strict aliasing problem\n");
        }
    }
    
    int main(void) {
        int b;
        f((struct MyType *)&b, &b);
    
        return 0;
    }
    

    用 GCC 5.4.0 编译它:

    $ gcc -O2 -o main main.c
    $ ./main
    Strict aliasing problem
    

    2。没有前向声明,没有may_alias(错误行为)

    同上。

    3。前向声明,may_alias(不会编译)

    struct __attribute__((may_alias)) MyType;  // Forward declaration here, with may_alias.
    
    struct __attribute__((may_alias)) MyType {
        short a;
    };  // Full definition here, with may_alias.
    

    用 GCC 5.4.0 编译它:

    $ gcc -O2 -o main main.c
    main.c:11:10: error: conflicting types for ‘foo’
         void foo(struct MyType *my_type, int *b)
              ^
    main.c:5:10: note: previous declaration of ‘foo’ was here
         void foo(struct MyType *, int *b);
    

    似乎 GCC 认为 struct MyType; 是一种不同的类型。但是,无论如何我都没有找到将may_alias 属性添加到前向声明中。根据the order doc

    如果结构体、联合体或枚举类型的内容没有在使用属性说明符列表的说明符中定义——即在诸如struct attribute(( foo)) bar 没有后面的左大括号。

    一个潜在的解决方法是像这样声明foo

    void foo(struct MyType __attribute__((may_alias)) *, int *b);
    

    但是,这不是一个好的解决方案,看起来像这样的语法might be not yet supported:

    再次注意,这不适用于大多数属性;例如,尚不支持使用上面给出的“aligned”和“noreturn”属性。

    虽然它可以编译,但 may_alias 属性不起作用:

    $ gcc -O2 -o main main.c
    $ ./main
    Strict aliasing problem
    

    4。没有前向声明,may_alias(好)

    这是唯一可行的方法。

    $ gcc -O2 -o main main.c
    $ ./main
    $
    

    但是,就我而言,需要前向声明。我的解决方法是使用void * 而不是struct MyType *

    // In the .h file, no definition of MyType yet.
    void foo(void *my_type, int *b);
    
    // In the .c file, has the definition of MyType.
    void foo(void *t, int *b)
    {
        struct MyType *my_type = t;
    
        // ...
    }
    

    这一点都不优雅,但却是目前唯一可行的方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-31
      相关资源
      最近更新 更多