Как скомпилировать C код с анонимными структурами / профсоюзы?


Я могу сделать это в c++ / g++:

struct vec3 { 
    union {
        struct {
            float x, y, z;
        }; 
        float xyz[3];
    }; 
};

затем,

vec3 v;
assert(&v.xyz[0] == &v.x);
assert(&v.xyz[1] == &v.y);
assert(&v.xyz[2] == &v.z);

будет работать.

как это сделать в c с gcc? У меня есть

typedef struct {
    union {
        struct {
            float x, y, z;
        };
        float xyz[3];
    };
} Vector3;

но я получаю ошибки все вокруг, в частности

line 5: warning: declaration does not declare anything
line 7: warning: declaration does not declare anything
10 61

10 ответов:

согласно http://gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html#Unnamed-Fields

-fms-extensions включит функцию, которую вы (и я) хотите.

(этот ответ относится к C99, а не C11).

C99 не имеет анонимных структур или союзов. Вы должны назвать их:

typedef struct {
    union {
        struct {
            float x, y, z;
        } individual;
        float xyz[3];
    } data;
} Vector3;

и затем вы должны использовать имя при доступе к ним:

assert(&v.data.xyz[0] == &v.data.individual.x);

в этом случае, поскольку ваша структура верхнего уровня имеет один элемент типа union, вы можете упростить это:

typedef union {
    struct {
        float x, y, z;
    } individual;
    float xyz[3];
} Vector3;

и доступ к данным теперь будет:

assert(&v.xyz[0] == &v.individual.x);

новый стандарт C11 будет поддерживать анонимные структуры и объединения, см. предисловие пункт 6 проекта от апреля 2011 года.

http://en.wikipedia.org/wiki/C1X

странная часть заключается в том, что как gcc, так и clang теперь поддерживают анонимные структуры и союзы в режиме C89 и C99. В моей машине никаких предупреждений не появляется.

можно также всегда делать следующее:

typedef struct
{
    float xyz[0];
    float x, y, z;
}Vec3;

массив нулевой длины не выделяет никакого хранилища и просто говорит C "указать на то, что объявлено следующим."Тогда вы можете получить доступ к нему так же, как и к любому другому массиву:

int main(int argc, char** argv)
{
    Vec3 tVec;
    for(int i = 0; i < 3; ++i)
    {
        tVec.xyz[i] = (float)i;
    }

    printf("vec.x == %f\n", tVec.x);
    printf("vec.y == %f\n", tVec.y);
    printf("vec.z == %f\n", tVec.z);

    return 0;
}

результат:

vec.x == 0.000000
vec.y == 1.000000
vec.z == 2.000000

Если вы хотите быть дополнительным параноиком, вы можете вручную указать стратегию упаковки данных в соответствии с вашей платформой.

анонимные объединения-это особенность языка C++. Язык C не имеет анонимных союзов.

анонимные структуры не существуют ни в C, ни в C++.

объявление, которое вы представили в своем вопросе, может быть скомпилировано с помощью gcc c++ complier, но это будет просто расширение для компилятора, которое не имеет ничего общего ни со стандартным C, ни со стандартным c++.

кроме того, независимо от того, как вы его реализуете, ни язык C, ни язык C++ не гарантируют, что ваш утверждения будут держаться.

Я могу сделать это в GCC без предупреждения

typedef union {
    struct { // human-friendly access
        float x;
        float y;
        float z;
        float w;
    };
    float xyz[3];
    struct { // human-friendly access
        float r;
        float g;
        float b;
        float a;
    };
    float rgb[3];
} Vector4f;

int main()
{
    Vector4f position, normal, color;
    // human-friendly access
    position.x = 12.3f;
    position.y = 2.f;
    position.z = 3.f;
    position.w = 1.f;

    normal.x = .8f;
    normal.y = .9f;
    normal.z = .1f;
    normal.w = 1.f;

    color.r = 1.f;
    color.g = .233f;
    color.b = 2.11f;
    color.a = 1.1f;

    // computer friendly access
    //some_processor_specific_operation(position.vec,normal.vec);
    return 0;
}

C:\>gcc vec.c-Wall

C:\>gcc --version gcc (GCC) 4.4.0 Copyright (C) 2009 Free Software Foundation, Inc. Это свободное программное обеспечение; источник смотри Условия копирования. нет гарантия; даже не для товарности или пригодности для определенной цели.

анонимные союзы не поддерживаются в C.

Также обратите внимание, что если вы заявляете об этом так:

typedef struct {
    union {
        struct {
            float x, y, z;
        } individual;
        float xyz[3];
    } data;
} Vector3;

делаешь

Vector3 v;
v.data.xyz[0] = 5;

float foo = v.data.individual.x;

- это неопределенное поведение. Вы можете получить доступ только к последнему назначенному члену профсоюза. В вашем случае использование объединения является неправильной и плохой практикой кодирования, поскольку она зависит от многих вещей, которые не указаны в стандарте (заполнение...).

В C вы предпочтете что-то вроде этого:

typedef struct {
    float v[3];
} Vec3;

и если вы не хочу использовать v[x] вы можете рассмотреть:

#define X(V) ((V).v[0])

Vec3 v;
X(v) = 5.3;
printf("%f\n", X(v));

диалект GNU C поддерживает анонимные структуры / объединения, но по умолчанию GCC компилируется с использованием какого-то стандарта C. Чтобы использовать диалект GNU, поместите "- std=gnu99" в командной строке.

неопознанные члены структуры, не являющиеся стандартом ANSI/ISO C99, объясняют это, но я нахожу, что на некоторых портах компилятора GNU C 2 происходит забавная вещь.X. X версии, используя неидентифицированные элементы структуры работает, он находит их, не говорит такие вещи, как " x не является членом union\struct y, что такое x?", в других случаях, это ol '"x не определен", "x не является членом структуры", черт возьми, я клянусь, что видел "указатель на неизвестное" однажды, из-за этого.

Так что я, профессионально пошел бы с все остальные на этом и просто эфире дают struct\Union member идентификатор, или в случае союзов, тщательно перестраивают код, чтобы союз заканчивался идентифицированным членом идентифицированной структуры, а члены, которые были встроены в неопознанную структуру исходного союза, становятся членами идентифицированной структуры и тщательно используются с идентифицированным членом Союза. Но в тех случаях, когда последний метод не был бы работоспособной заменой, я бы просто дал раздражает структура идентификатора и двигаться дальше.

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

#define x    ___fl_fld[0]
#define y    ___fl_fld[1]
#define z    ___fl_fld[2]
#define w    ___fl_fld[3]
#define r    ___fl_fld[0]
#define g    ___fl_fld[1]
#define b    ___fl_fld[2]
#define a    ___fl_fld[3]
typedef union {
    float ___fl_fld[4];
    float xyz[3];
    float rgb[3];
} Vector3;

вы можете получить доступ к структуре следующим образом:

Vector3 v;
assert(&v.x == &v.r); //Should return true

чтобы закончить, это будет соединение нескольких типов, совместимое с C99:

#define u8llsb __u8[0]
#define u8lmsb __u8[1]
#define u8mlsb __u8[2]
#define u8mmsb __u8[3]
#define u16lsb __u16[0]
#define u16msb __u16[1]
#define u16    __u16[0]
#define u8lsb  __u8[0]
#define u8msb  __u8[1]

typedef union {
    uint32_t u32;
    int32_t  i32;
    uint16_t  __u16[2];
    uint8_t   __u8[4];
} multitype_t;

multitype_t Var;
var.u32;
var.i32;
var.u8llsb;
/* etc. */