Подтвердить что ты не робот

Можем ли мы использовать указатель в объединении?

Если нет, то почему? Использование союза над структурой?

4b9b3361

Ответ 1

Вы можете использовать любой тип данных в объединении, нет ограничений.

Что касается использования объединений над структурами, структуры излагают свои данные последовательно в памяти. Это означает, что все их подкомпоненты являются отдельными.

С другой стороны, союзы используют одну и ту же память для всех своих подкомпонентов, поэтому только один может существовать одновременно.

Например:

                                 +-----+-----+
struct { int a; float b }  gives |  a  |  b  |
                                 +-----+-----+
                                    ^     ^
                                    |     |
                 memory location:  150   154
                                    |
                                    V
                                 +-----+
union { int a; float b }  gives  |  a  |
                                 |  b  |
                                 +-----+

Структуры используются там, где "объект" состоит из других объектов, таких как точечный объект, состоящий из двух целых чисел, которые являются координатами x и y:

typedef struct {
    int x;           // x and y are separate
    int y;
} tPoint;

Союзы обычно используются в ситуации, когда объект может быть одной из многих вещей, но только по одному, например, система хранения без тиков:

typedef enum { STR, INT } tType;
typedef struct {
    tType typ;          // typ is separate.
    union {
        int ival;       // ival and sval occupy same memory.
        char *sval;
    }
} tVal;

Они полезны для экономии памяти, хотя в наши дни это все меньше и меньше беспокоит (кроме работы на низком уровне, например встроенные системы), поэтому вы не видите ее много.

Ответ 2

Хорошо, согласно 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. Но я подозреваю, что в этот момент поведение undefined.

Во всяком случае, смысл этого небольшого упражнения состоял в том, чтобы показать вам, что:

  • союзы могут использоваться для доступа к одному и тому же местоположению памяти с помощью другого модификатора типа.
  • Вы должны быть осторожны, что вы делаете, и понимаете базовый тип, который вы используете. Если вы собираетесь использовать указатели, остерегайтесь их модификации, поскольку вы можете начать указывать, кто знает что.

Я должен указать, что я вижу практическое использование somenewtype, но не для somepointer - это был надуманный пример, который, я уверен, сломал бы.