(Editado) Tanto gcc y MSVC permiten 'anónimos' structs/sindicatos, que podría resolver su problema. Por ejemplo:
union Pixel {
struct {unsigned char b,g,r,a;};
uint32_t bits; // use 'unsigned' for MSVC
}
foo.b = 1;
foo.g = 2;
foo.r = 3;
foo.a = 4;
printf ("%08x\n", foo.bits);
da (en Intel):
04030201
Esto requiere cambiar todas sus declaraciones de Pixel estructura a Pixel unión en su código original. Pero este defecto se puede fijar a través de:
struct Pixel {
union {
struct {unsigned char b,g,r,a;};
uint32_t bits;
};
} foo;
foo.b = 1;
foo.g = 2;
foo.r = 3;
foo.a = 4;
printf ("%08x\n", foo.bits);
Esto también funciona con VC9, la 'C4201 advertencia: la extensión no estándar utilizado: sin nombre struct/union'. Microsoft utiliza este truco, por ejemplo, en:
typedef union {
struct {
DWORD LowPart;
LONG HighPart;
}; // <-- nameless member!
struct {
DWORD LowPart;
LONG HighPart;
} u;
LONGLONG QuadPart;
} LARGE_INTEGER;
pero 'engañar' al suprimir la advertencia no deseado.
Si bien los ejemplos anteriores son correctos, si utiliza esta técnica con demasiada frecuencia, terminará rápidamente con un código que no se puede mantener.Cinco sugerencias para aclarar las cosas:
(1) Cambie el nombre bits
a algo más feo como union_bits
, para indicar claramente algo fuera de lo común.
(2) Volver a la fea fundido el OP rechazada, pero ocultar su fealdad en una macro o en una función en línea, como en:
#define BITS(x) (*(uint32_t*)&(x))
Pero esto rompería las estrictas reglas de alias. (Véase, por ejemplo, la respuesta de AndreyT:. C99 strict aliasing rules in C++ (GCC))
(3) Mantenga el definiton original de píxeles, pero hacer un mejor reparto:
struct Pixel {unsigned char b,g,r,a;} foo;
// ...
printf("%08x\n", ((union {struct Pixel dummy; uint32_t bits;})foo).bits);
(4) Pero eso es aún más feo. Puede solucionar este problema mediante un typedef
:
struct Pixel {unsigned char b,g,r,a;} foo;
typedef union {struct Pixel dummy; uint32_t bits;} CastPixelToBits;
// ...
printf("%08x\n", ((CastPixelToBits)foo).bits); // not VC9
Con VC9, o con gcc usando -pedantic, necesitará (no hacer uso esto con gcc --ver nota al final) :
printf("%08x\n", ((CastPixelToBits*)&foo)->bits); // VC9 (not gcc)
(5) Una macro quizás sea la preferida. En gcc, se puede definir un elenco unión a cualquier tipo dado muy claramente:
#define CAST(type, x) (((union {typeof(x) src; type dst;})(x)).dst) // gcc
// ...
printf("%08x\n", CAST(uint32_t, foo));
Con VC9 y otros compiladores, no hay typeof
, y pueden ser necesarios los punteros (no lo hacen uso esto con gcc nota --ver al final):
#define CAST(typeof_x, type, x) (((union {typeof_x src; type dst;}*)&(x))->dst)
auto-documentado, y más seguro. Y no también feo. Es probable que todas estas sugerencias se compilen con un código idéntico, por lo que la eficiencia no es un problema. Ver también mi respuesta relacionada: How to format a function pointer?.
Advertencia sobre gcc: Manual El GCC versión 4.3.4 (pero no versión 4.3.0) establece que este último ejemplo, con &(x)
, es un comportamiento indefinido . Ver http://davmac.wordpress.com/2010/01/08/gcc-strict-aliasing-c99/ y http://gcc.gnu.org/ml/gcc/2010-01/msg00013.html.
Raramente escuchas las palabras "unión" y "simplificar" en la misma oración ... –
Creo que aplicar la máscara 0xE0 no es equivalente a <= 0x10. En particular, 0x1F es mayor que 0x10 y aplicar la máscara arrojará 0x00 –
Y su rechazado 'este feo lío' \ * ((uint32_t \ *) & pixel) también rompería las reglas estrictas de aliasing. –