海湾合作委员会前瞻性声明和__may__alias

时间:2010-10-05 19:30:23

标签: c gcc

我正在尝试使用_ may _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'声明就在这里

有办法做到这一点吗?

2 个答案:

答案 0 :(得分:2)

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 { };

答案 1 :(得分:0)

经过数小时的实验,这似乎是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属性添加到转发声明中的方法。根据{{​​3}}:

  

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

可能的解决方法是像这样声明foo

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

但是,这不是一个好的解决方案,看起来像这样的语法the order doc

  

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

尽管可以编译,但是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;

    // ...
}

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