【问题标题】:Compatible types and structures in CC 中兼容的类型和结构
【发布时间】:2011-02-23 16:23:35
【问题描述】:

我有以下代码:

int main(void)
{
    struct { int x; } a, b;
    struct { int x; } c;
    struct { int x; } *p;

    b = a;   /* OK */
    c = a;   /* Doesn't work */
    p = &a;  /* Doesn't work */

    return 0;
}

在GCC(3.4.6)下编译失败,报错:

test.c:8: error: incompatible types in assignment
test.c:9: warning: assignment from incompatible pointer type

现在,据我了解(诚然来自 C99 标准),ac 应该是兼容类型,因为它们满足第 6.2.7 节第 1 段中的所有标准。我试过了用std=c99编译,无济于事。

大概我对标准的解释是错误的?

附录

顺便说一句,这个问题的出现是因为我想声明一些类似模板的宏来包装各种数据类型,而无需在任何地方声明命名类型/类型定义的开销,例如一个简单的例子:

#define LINKED_LIST(T)   \
    struct {             \
        T    *pHead;     \
        T    *pTail;     \
    }

...

LINKED_LIST(foo) list1;
LINKED_LIST(foo) list2;

...

LINKED_LIST(foo) *pList = &list1;  /* Doesn't work */

【问题讨论】:

    标签: c gcc type-conversion


    【解决方案1】:

    struct { int x; }是匿名结构标签,两个匿名结构不能有“同名”,这是类型兼容的必要条件。您可以使用typedef 声明与非匿名结构兼容的类型。

    struct tmp { int x; }; // declare structure tag
    typedef struct tmp type1;
    typedef struct tmp type2; // declare 3 types compatible with struct tmp
    typedef struct tmp type3; // and with each other
    
    type1 a, b;
    type2 c;
    type3 *p;
    b = a;
    c = a;
    p = &a;
    

    【讨论】:

    • 毫无疑问,您可以按照代码示例中的建议进行操作。但是,规范说“如果一个用标签声明......”。
    • 与 Oli 的注释相同,以 OP 为例,应该应用使用标签声明结构 not 的规则。
    【解决方案2】:

    看看draft specification,我猜你依赖于声明之后的条件:

    此外,如果它们的标签和成员满足以下要求,则在单独的翻译单元中声明的两种结构、联合或枚举类型是兼容的...

    我认为这些都在同一个 C 文件中声明的事实意味着它们在一个翻译单元中。

    据推测,这似乎保证了当两个 C 文件包含一个声明一个类型的标头时,该类型的实例将是兼容的。

    【讨论】:

    • 有趣的地方。我试图想出一个可以在 GCC 下测试这个理论的例子,但想不出一个能实践这个想法的例子。如果有例如void foo(struct {int x;}) 在标头中,尝试执行 struct {int x;} a; ... 富(一);会失败,因为这都在同一个翻译单元内!
    • 是的,这确实是我目前让编译器满意的解决方案。我对此并不完全满意,因为我不确定我现在是否无意中违反了严格别名规则!
    • 我很确定该标准有意将兼容性限制在定义位于不同翻译单元中的情况下(在这种情况下,它不会影响使用指针不能相互别名以进行优化的假设的能力)。
    • 如前所述,6.2.7p1 仅适用于跨翻译单元的结构兼容性,而不适用于同一文件内。在同一个文件中,6.7.2.3p5 表示 每个不包含标记的结构、联合或枚举类型的声明都声明了一个不同的类型。 此外,6.7.2.1p7 表示 存在struct-or-union-specifier 中的 struct-declaration-list 在翻译单元内声明一个新类型。
    • @Oli(续)以上两个语句都支持每个翻译单元只能定义一个结构的想法。
    【解决方案3】:

    Compatibility of structures, unions, and enumerations

    在单个源文件中,每个结构或联合定义 创建一个新的类型,既不相同也不兼容任何 其他结构或联合类型。但是,类型说明符是 对先前定义的结构或联合类型的引用是相同的 类型。标签将引用与定义相关联,并且 有效地充当类型名称。为了说明这一点,只有类型 在这个例子中,结构 j 和 k 是兼容的:

    struct   { int a; int b; } h;
    struct   { int a; int b; } i;
    struct S { int a; int b; } j;
    struct S k;
    

    兼容的结构可以相互分配。

    【讨论】:

      【解决方案4】:

      有趣的是,Clang 给出了以下内容:

      error: incompatible type assigning 'struct <anonymous>', expected 'struct <anonymous>'
      
      warning: incompatible pointer types assigning 'struct <anonymous> *', expected 'struct <anonymous> *'
      

      似乎如果声明了两个(或更多)匿名结构,那么编译器会执行一些内部魔法来指定哪个特定的匿名结构也被引用。

      【讨论】:

        【解决方案5】:

        考虑到第 6.2.7 段(兼容类型)和 6.5.16.1 段(分配规则),我的理解和你一样。

        看起来你的代码 GCC 的行为就像你的结构定义用不同的标签标记(事实并非如此)。在这种情况下,类型将不兼容。但是它看起来仍然像一个 gcc 错误。

        来自其他实现 C99 标准的编译器的反馈?

        【讨论】:

        • 这不是错误。您在问题的第一个代码片段中有 3 种不同的匿名结构类型,这三种类型不兼容。
        猜你喜欢
        • 2020-01-10
        • 1970-01-01
        • 2016-01-19
        • 2013-05-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多