在联盟中,不愿命名的未命名结构的成员是错误或GCC错误

Are identically named members of unnamed structs in a union an error or a GCC bug?

本文关键字:错误 结构 未命名 成员 GCC 联盟      更新时间:2023-10-16

以下代码可以在Visual C 中成功编译。我喜欢它,很甜!

#include <stdio.h>
#ifdef _MSC_VER
    #pragma warning(push)
    #pragma warning(disable:4201)
    #pragma pack(push,1)
    #define PACKED
#else
    #define PACKED __attribute__ ((__packed__))
#endif
union A {
    struct {
        int a:1;
        int b:2;
        int c1:29;
    }PACKED;
    struct {
        int a:1;
        int b:2;
        int c2:28;
        int d:1;
    }PACKED;
    int val;
}PACKED;
#ifdef _MSC_VER
    #pragma pack(pop)
    #pragma warning(pop)
#endif
#undef PACKED
int main(){
    A test;
    test.val = 0x1078FFF7;
    printf("sizeof(A): %d, test.a: %d.n", sizeof(A), test.a);
    return -1;
}

输出使用MSC构建的文件:

sizeof(A): 4, test.a: -1.

但在GCC中,包括最新的GCC-7,它未能编译:(

struct.cpp:13:15: error: redeclaration of ‘signed char:1 A::<unnamed struct>::a’
     int a:1;
           ^
struct.cpp:7:15: note: previous declaration ‘signed char:1 A::<unnamed struct>::a’
     int a:1;
           ^
struct.cpp:14:15: error: redeclaration of ‘signed char:2 A::<unnamed struct>::b’
     int b:2;
           ^
struct.cpp:8:15: note: previous declaration ‘signed char:2 A::<unnamed struct>::b’
     int b:2;
           ^

是GCC中的错误?


感谢您的评论,我只是理解这个问题对C可能是无效的。但是对于C 部分,我仍然担心。我个人喜欢Visual C 编译行为,它可以在我的方案中节省大量代码

6.7.2.1结构和联合指示符说:

一个不愿透露姓名的成员,其类型说明符是一个没有标签的结构指定符,称为匿名结构。一个不愿透露姓名的成员,其类型指定符是没有标签的联合规范符,称为匿名联盟。匿名结构或联合的成员被认为是包含结构或联合的成员。,如果包含结构或联合也是匿名的,则递归适用。

(强调我的(

因此,基于这本质上是好像您有:

union A
{
    int a:1;
    int b:2;
    int c1:29;
    int a:1;
    int b:2;
    int c2:28;
    int d:1;
    int val;
};

这显然是无效的,而GCC正确地发出了诊断。

它不是gcc中的错误。

语言标准不允许这样做。但是Visual C 确实可以,如果有任何内容可以允许Windows标题编译。实际上,如果您不想使用Microsoft编译器来编译Windows标题,则需要使用

#define NONAMELESSUNION

#include <windows.h>之前。当时这似乎是个好主意。

参考:什么是匿名结构,更重要的是,我如何告诉Windows.h停止使用它们?

已在P.P.的答案和评论中进行了讨论,即您想要的不正确,而海湾合作委员会的行为也正确。但是,满足您需求的简单解决方法可能是您在第二个结构中重命名ab

union A {
    struct {
        int a:1;
        int b:2;
        int c1:29;
    }PACKED;
    struct {
        int unused_name_a:1;
        int unused_name_b:2;
        int c2:28;
        int d:1;
    }PACKED;
    int val;
}PACKED;

这在GCC和Clang中对我有用,并且仍然应该让您的技巧很好地工作。