Ну, в соответствии с ISO / IEC 9899: TC3 (стандарт C99):
Тип объединения описывает перекрывающийся непустой набор объектов-членов, каждый из которых
который имеет необязательно указанное имя и, возможно, отдельный тип.
Короче говоря, пространство памяти членов объединения перекрывается, и имена, которые вы даете членам объединения, позволяют вам читать память в этом месте по размеру. Рассмотрим:
#include <stdio.h>
#include <stdint.h>
typedef union
{
struct
{
uint8_t a;
uint8_t b;
uint8_t c;
uint8_t d;
};
uint32_t x;
} somenewtype;
typedef union
{
uint32_t* p;
uint8_t* q;
} somepointer;
int main(int argc, char** argv)
{
uint32_t r;
uint8_t s;
somenewtype z;
somepointer p;
r = 0x11223344; s = 0x11;
z.x = 0x11223344;
p.p = &r;
p.q = &s;
printf("%x%x%x%x\n", z.d, z.c, z.b, z.a);
printf("%x %x\n", *(p.p), *(p.q));
}
В первом printf мы выводим 8-битные части 32-битного целого числа. Надеемся, конечно, что в этой анонимной структуре нет отступов.
Во втором printf? Мне пришлось пройти через использование GDB, чтобы понять, но я сделал:
p.p = (uint32_t *) 0x7fffffffde5c;
p.q = (uint8_t *) 0x7fffffffde5b "\021D3\"\021P\337\377\377\377\177";
p.p = (uint32_t *) 0x7fffffffde5b;
Конечно, указатели имеют одинаковый размер, поэтому при присваивании p.q
адрес p.p
перезаписывается. Я сильно подозреваю, что разыменование адреса 32-разрядного целого числа для 8-разрядного указателя печатает «все, что находится в этом месте + размер 32 бита», что, кстати, для меня случайно оказывается 22334411
. Но я подозреваю, что в этот момент поведение не определено.
В любом случае, смысл этого маленького упражнения состоял в том, чтобы показать вам, что:
- объединения могут использоваться для доступа к одной и той же ячейке памяти через другой модификатор типа.
- Вы должны быть осторожны в том, что вы делаете, и понимать базовый тип, который вы используете. Если вы собираетесь использовать указатели, остерегайтесь их модификации, поскольку вы можете начать указывать, кто что знает.
Я должен отметить, что я вижу практическое использование для somenewtype
, но не для somepointer
- это был надуманный пример, который я был почти уверен, что сломается.