Ответ 1
согласно http://gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html#Unnamed-Fields
-fms-extensions
будет включать функцию, которую вы (и я) хотите.
Я могу сделать это в С++/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
согласно 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);
В этом случае, поскольку ваша структура верхнего уровня имеет единственный элемент объединения типов, вы можете упростить это:
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, ни в С++.
Объявление, которое вы представили в своем вопросе, может быть скомпилировано с помощью GCC С++, но это будет просто расширение для компилятора, которое не имеет ничего общего ни с стандартным 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 --версия 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;
Это поведение undefined. Вы можете получить доступ только к последнему назначенному члену объединения. В вашем случае использование объединения является неправильной и плохой практикой кодирования, поскольку оно зависит от многих вещей, которые не указаны в стандарте (padding...).
В 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 Compiler 2.xx, используя неиспользуемые элементы структуры, находит их, не говорит "x не является членом union\struct y, что такое x?", в других случаях это ol "x is undefined", "x не является членом структуры", черт возьми, я клянусь, что увидел "указатель на неизвестный" один раз назад, из-за этого.
Итак, я профессионально поеду со всеми остальными на этом и просто эфир предоставит члену struct\union идентификатору, или, в случае UNION, тщательно перестройте код, чтобы профсоюз оказался идентифицированным элементом идентифицированной структуры и члены, которые были встроены в неопознанную структуру первоначального союза, становятся членами идентифицированной структуры и тщательно используются с идентифицированным членом профсоюза. Но в этих случаях последний метод не был бы выполнимым заменителем, я просто дал бы досадную структуру идентификатору и двигался дальше.
Я могу предложить интересное обходное решение, чтобы избежать слишком большого количества полей внутри структуры. Один из них предупреждает об именах, называемых define, так как он может создавать конфликты.
#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. */