Являются ли идентично названные члены неназванных структур в объединении ошибкой или ошибкой GCC?

Следующий код можно скомпилировать в 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++, она может сохранить тонны кода в моем сценарии

Ответ 1

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 правильно выдает диагностику.

Ответ 2

Это не ошибка в GCC.

Языковой стандарт этого не позволяет. Но Visual C++ делает, если что угодно, чтобы разрешить компиляцию заголовков Windows. На самом деле, если вы не хотите использовать компилятор Microsoft для компиляции заголовков Windows, вам необходимо использовать

#define NONAMELESSUNION

перед #include <windows.h>. В то время это, вероятно, казалось хорошей идеей.

Справка: Что такое анонимные структуры, и что еще более важно, как я могу сказать windows.h прекратить их использование?

Ответ 3

В ответе PP и комментариях обсуждалось, что вы хотите не правильно, и GCC ведет себя правильно. Но легкое обходное решение, которое удовлетворяет ваши потребности, может заключаться в том, что вы переименовываете a и b во второй структуре:

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 и все равно должно позволить вашему трюку работать хорошо.