c++ - lenguaje - ¿Cómo compilar el código C con estructuras/uniones anónimas?
funciones con estructuras en c (10)
Puedo hacer esto en c ++ / g ++:
struct vec3 {
union {
struct {
float x, y, z;
};
float xyz[3];
};
};
Entonces,
vec3 v;
assert(&v.xyz[0] == &v.x);
assert(&v.xyz[1] == &v.y);
assert(&v.xyz[2] == &v.z);
trabajará.
¿Cómo se hace esto en c con gcc? yo tengo
typedef struct {
union {
struct {
float x, y, z;
};
float xyz[3];
};
} Vector3;
Pero tengo errores en todo, específicamente
line 5: warning: declaration does not declare anything
line 7: warning: declaration does not declare anything
(Esta respuesta se aplica a C99, no a C11).
C99 no tiene estructuras o uniones anónimas. Tienes que nombrarlos:
typedef struct {
union {
struct {
float x, y, z;
} individual;
float xyz[3];
} data;
} Vector3;
Y luego debes usar el nombre al acceder a ellos:
assert(&v.data.xyz[0] == &v.data.individual.x);
En este caso, debido a que su estructura de nivel superior tiene un único elemento de tipo unión, podría simplificar esto:
typedef union {
struct {
float x, y, z;
} individual;
float xyz[3];
} Vector3;
y acceder a los datos ahora se convierte en:
assert(&v.xyz[0] == &v.individual.x);
El dialecto GNU de C soporta estructuras / uniones anónimas, pero por defecto GCC compila usando algún tipo de estándar C. Para usar el dialecto GNU, ponga "-std = gnu99" en la línea de comando.
El nuevo estándar C11 apoyará estructuras y uniones anónimas, véase el prólogo del párrafo 6 del borrador de abril de 2011.
http://en.wikipedia.org/wiki/C1X
La parte extraña es que tanto gcc como clang admiten ahora estructuras y uniones anónimas en el modo C89 y C99. En mi máquina no aparece ninguna advertencia.
Las uniones anónimas son una característica del lenguaje C ++. El lenguaje C no tiene uniones anónimas.
Las estructuras anónimas no existen ni en C ni en C ++.
La declaración que presentó en su pregunta podría compilarse con el compilador GCC C ++, pero sería solo una extensión específica del compilador, que no tiene nada que ver ni con el estándar C ni con el estándar C ++.
Además de eso, independientemente de cómo lo implemente, ni el lenguaje C ni C ++ garantiza que sus afirmaciones se mantendrán.
Las uniones de Anonymouse no son apoyadas en C.
También tenga en cuenta que si lo declara de esta manera:
typedef struct {
union {
struct {
float x, y, z;
} individual;
float xyz[3];
} data;
} Vector3;
Obra
Vector3 v;
v.data.xyz[0] = 5;
float foo = v.data.individual.x;
Es un comportamiento indefinido Solo puede acceder al último miembro de la unión asignado. En su caso, usar una unión es una práctica de codificación incorrecta y mala ya que depende de muchas cosas que no están especificadas en el estándar (relleno ...).
En C preferirás algo como esto:
typedef struct {
float v[3];
} Vec3;
Y si no desea usar v [x], podría considerar:
#define X(V) ((V).v[0])
Vec3 v;
X(v) = 5.3;
printf("%f/n", X(v));
Los miembros de estructuras no identificadas que no son ANSI / ISO C99 explican esto, pero encuentro algo curioso: en algunos puertos de las versiones de GNU C Compiler 2.xx, el uso de elementos de estructura no identificados funciona, los encuentra, no dice cosas como " x no es miembro de union / struct y, ¿qué es x? ", otras veces, es el viejo" x no está definido "," x no es miembro de struct ", diablos juro que vi un" puntero a desconocido " "una vez hace un tiempo, debido a esto.
Así que yo, profesionalmente, iría con todos los demás en esto y simplemente le daría al miembro struct / union un identificador, o en el caso de UNIONs, reorganizaría cuidadosamente el código para que la unión termine siendo un miembro identificado de una estructura identificada y los miembros que se incluyeron en la estructura no identificada de la unión original, se convirtieron en miembros de la estructura identificada y se usan cuidadosamente con el miembro identificado de la unión. Pero en esos casos si el último método no fuera un sustituto viable, simplemente daría un identificador a la estructura annoynous y seguiría adelante.
Puedo hacer esto en GCC sin previo aviso
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. Esto es software libre; ver la fuente de las condiciones de copia. NO hay garantía; ni siquiera para COMERCIABILIDAD o IDONEIDAD PARA UN PROPÓSITO PARTICULAR.
Puedo sugerir una solución interesante para evitar demasiados campos dentro de la estructura. Se recomienda advertir acerca de simplemente named define, ya que podría crear conflictos.
#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;
Podrías acceder a la estructura de esta manera:
Vector3 v;
assert(&v.x == &v.r); //Should return true
Para finalizar, esta sería una unión de tipo múltiple compatible con 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. */
También se puede hacer siempre lo siguiente:
typedef struct
{
float xyz[0];
float x, y, z;
}Vec3;
La matriz de longitud cero no asigna ningún almacenamiento, y solo le dice a C que "apunte a lo que sea lo siguiente que se declare". Entonces, puede acceder a él como cualquier otra matriz:
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;
}
Resultado:
vec.x == 0.000000
vec.y == 1.000000
vec.z == 2.000000
Si desea ser más paranoico, puede especificar manualmente la estrategia de empaque de datos para adaptarse a su plataforma.
de acuerdo con http://gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html#Unnamed-Fields
-fms-extensions
habilitará la característica que usted (y yo) desee.