Произвольный доступ к членам массива союзов - PullRequest
0 голосов
/ 29 августа 2018

Упрощенный пример:

typedef union {
    int foo;
    char* bar;
} int_or_str;

void baz() {
    int_or_str* bogus = malloc(sizeof(int_or_str) * 43);
    bogus[42].bar = "test";
    printf("%s\n", bogus[42].bar);
}
  1. Если это сработает, будет ли компилятор считать, что все 42 члена bogus являются указателями на символы? (Очевидно, я мог бы попробовать это, но акцент на «должен»).
  2. Определяется ли вообще, что происходит, когда вы обращаетесь к массиву союзов таким образом?
  3. Предположим, я хотел получить массив союзов, которые на самом деле содержат значения разных размеров, это законно? (Я мог бы сохранить макет отдельно и вычислить смещение, если бы был уверен, как члены объединения размещаются в памяти).

Если вас интересует мотивация для этого вопроса: в основном, я пытаюсь найти решение для структуры, определенной во время выполнения. Моя идея заключалась в том, чтобы иметь массив союзов для представления структурных полей, а также некоторую запись метаданных о том, как получить доступ к этим полям.

1 Ответ

0 голосов
/ 29 августа 2018

объявление 1: Да, это будет работать.

объявление 2: да, оно идеально определено.

объявление 3: да, это законно.

Вся идея union заключается в том, что он может содержать различные типы элементов. Размер объединения будет размером самого большого элемента в объединении. В 64-битной системе это, вероятно, будет размер char *.

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

Но, как сказал Том, вы не можете знать, какой тип элемента в данный момент хранится; должна быть внешняя причина (информация), по которой вы это знаете. Если это важно знать, вы должны хранить информацию в структуре данных, например:

typedef struct {
    int whatisthis;
    union {
        int foo;
        char *bar;
    } u;
} int_or_str;

и установите его следующим образом:

int_or_str example;
example.whatisthis= 1;
example.u.foo= 1;

example.whatisthis= 2;
example.u.bar= "test";

и доступ как:

if (example.whatisthis==1) printf("%d\n", example.u.foo);
if (example.whatisthis==2) printf("%s\n", example.u.bar);
...