Использование макроса в определении анонимной структуры C11

Типичный способ C99 для расширения структуры выглядит примерно так:

struct Base {
    int x;
    /* ... */
};

struct Derived {
    struct Base base_part;
    int y;
    /* ... */
};

Затем мы можем преобразовать экземпляр struct Derived * в struct Base *, а затем получить доступ к x.

Я хочу получить доступ к базовым элементам struct Derived * obj; напрямую, например, obj->x и obj->y. C11 предоставляет расширенные структуры, но, как объяснено здесь, мы можем использовать эту функцию только с анонимными определениями. . Тогда как насчет написать

#define BASE_BODY { \
    int x; \
}

struct Base BASE_BODY;

struct Derived {
    struct BASE_BODY;
    int y;
};

Затем я могу получить доступ к базовым членам так же, как к производным, без каких-либо приведения или промежуточных членов. Я могу привести производный указатель к базовому указателю, если это необходимо.

Это приемлемо? Есть ли подводные камни?


person marmalmad    schedule 10.11.2014    source источник
comment
В качестве альтернативы вы можете рассмотреть возможность использования typedef (см. этот ответ) через параметр -fms-extensions в gcc или clang, но это нестандартно.   -  person Grzegorz Szpetkowski    schedule 10.11.2014


Ответы (1)


Есть подводные камни.

Учитывать:

#define BASE_BODY { \
    double a; \
    short b; \
}

struct Base BASE_BODY;

struct Derived {
    struct BASE_BODY;
    short c;
};

В некоторых реализациях это может быть sizeof(Base) == sizeof(Derived), но:

struct Base {
    double a;
    // Padding here
    short b;
}

struct Derived {
    double a;
    short b;
    short c;
};

Нет никакой гарантии, что структура памяти в начале будет такой же. Поэтому вы не можете передать этот тип Derived * функции, ожидающей Base *, и ожидать, что она сработает.

И даже если заполнение не испортит макет, все еще существует потенциальная проблема с представлением ловушки:

Если снова sizeof(Base) == sizeof(Derived), но c заканчивается областью, которая покрыта отступом в конце Base. Передача указателя этой структуры в функцию, которая ожидает Base* и изменяет его, также может повлиять на биты заполнения (заполнение имеет неопределенное значение), таким образом, возможно, повреждая c и, возможно, даже создавая представление ловушки.

person user694733    schedule 10.11.2014
comment
Это так. Я помещаю другой пакет #pragma перед определениями структур и ужасно испорченным результатом преобразования. - person marmalmad; 10.11.2014