(Отредактировано) Оба gcc и MSVC допускают «анонимные» структуры/объединения, которые могут решить вашу проблему. Например:
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);
дает (на Intel):
04030201
Для этого необходимо изменить все объявления о STRUCT Pixel в накидной Pixel в исходном коде. Но этот дефект может быть исправлен с помощью:
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);
Это также работает с VC9 с «предупреждением C4201: нестандартное расширение используется: безымянные структуры/объединение». Microsoft использует этот прием, например, в:
typedef union {
struct {
DWORD LowPart;
LONG HighPart;
}; // <-- nameless member!
struct {
DWORD LowPart;
LONG HighPart;
} u;
LONGLONG QuadPart;
} LARGE_INTEGER;
, но они «обманывают», подавляя нежелательное предупреждение.
Хотя приведенные выше примеры в порядке, если вы слишком часто используете эту технику, вы быстро получите недостижимый код.Пять предложений, чтобы сделать вещи более ясными:
(1) Измените имя bits
на что-то уродливое, например union_bits
, чтобы четко обозначить что-то необычное.
(2) Вернуться к уродливому гипсе ОП отвергнут, но скрыть свое уродство в макросе или в встроенной функции, как:
#define BITS(x) (*(uint32_t*)&(x))
Но это будет нарушать строгие правила наложения спектров. (См, например, ответ AndreyT в:. C99 strict aliasing rules in C++ (GCC))
(3) Храните Definiton пикселя, но сделать лучше бросок:
struct Pixel {unsigned char b,g,r,a;} foo;
// ...
printf("%08x\n", ((union {struct Pixel dummy; uint32_t bits;})foo).bits);
(4) Но это даже уродливее. Вы можете исправить это с помощью 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
С VC9, или с помощью GCC -pedantic, вам нужно (не использовать это с Gcc --see примечание в конце) :
printf("%08x\n", ((CastPixelToBits*)&foo)->bits); // VC9 (not gcc)
(5) Возможно, макрос может быть предпочтительным. В GCC, вы можете определить накидной оттенок любого данного типа очень аккуратно:
#define CAST(type, x) (((union {typeof(x) src; type dst;})(x)).dst) // gcc
// ...
printf("%08x\n", CAST(uint32_t, foo));
С VC9 и других компиляторов, нет typeof
, и могут быть необходимы указатели (не использовать это с НКУ --see примечание в конце):
#define CAST(typeof_x, type, x) (((union {typeof_x src; type dst;}*)&(x))->dst)
самодокументирован, и безопаснее. И не тоже уродливый. Все эти предложения, скорее всего, будут скомпилированы для идентичного кода, поэтому эффективность не является проблемой. См. Также мой ответ: How to format a function pointer?.
Предупреждение о НКУ: ССАГПЗ Руководство по версии 4.3.4 (но не версия 4.3.0) утверждает, что этот последний пример, с &(x)
, является неопределенное поведение. См. http://davmac.wordpress.com/2010/01/08/gcc-strict-aliasing-c99/ и http://gcc.gnu.org/ml/gcc/2010-01/msg00013.html.
Вы редко слышите слова «объединение» и «упрощение» в том же предложении ... –
Я считаю, что применение маски 0xE0 не эквивалентно <= 0x10. В частности, 0x1F больше 0x10, и применение маски даст 0x00 –
И ваш отклоненный «этот уродливый беспорядок» \ * ((uint32_t \ *) & pixel) также нарушит строгие правила псевдонимов. –