联合中未命名结构的同名成员是错误还是GCC错误?

时间:2018-04-04 08:11:06

标签: c++ gcc language-lawyer

以下代码可以在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;
           ^

这是海湾合作委员会的错误吗?

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

3 个答案:

答案 0 :(得分:28)

6.7.2.1 Structure and union specifiers说:

  

一个未命名的成员,其类型说明符是一个没有标记的结构说明符,称为匿名结构;一个未命名的成员,其类型说明符是一个没有标记的联合说明符,称为匿名联合。 匿名结构或联合的成员被视为包含结构或联合的成员。如果包含的结构或联合也是匿名的,则递归应用。

(强调我的)

基于此,它基本上就像你有:

    private readonly IDistributedCache _cache;
            public Constructor(IDistributedCache cache)
            {
                _cache = cache;
            }

     public async Task<MyModel> GetWebApiData(double? latitude, double? longitude)
        {    
               var key = $"MyKey";
                var cachedValue = await _cache.GetAsync(key);

                if (cachedValue == null)
                {
                    data = "CallWebApi"
                    await SetDataToCache(key, data);
                }
                else
                {
                    data = JsonConvert.DeserializeObject<MyModel>(Encoding.UTF8.GetString(cachedValue));
                }
}

    public async Task SetDataToCache(string key, MyModel data)
            {
                if (data != null)
                {
                    var json = JsonConvert.SerializeObject(data);
                    await _cache.SetAsync(key, Encoding.ASCII.GetBytes(json), new DistributedCacheEntryOptions()
                    {
                        AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10)
                    });
                }
            }

这显然是无效的,gcc正确地发出诊断信息。

答案 1 :(得分:19)

这不是海湾合作委员会的错误。

语言标准不允许这样做。但是,如果允许编译Windows头文件,Visual C ++会这样做。实际上,如果您不想使用Microsoft编译器来编译Windows标头,那么您需要使用

#define NONAMELESSUNION
#include <windows.h>之前

。当时这似乎是一个好主意。

参考: What are anonymous structs, and more importantly, how do I tell windows.h to stop using them?

答案 2 :(得分:1)

在P.P。的答案和评论中已经讨论过,你想要的并不正确,而且GCC的行为正确。但是,满足您需求的简单解决方法可能是您在第二个结构中重命名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中对我有用,并且仍然可以让你的技巧很好地工作。

相关问题