Итак, C99 благословил часто используемый "элемент гибкого массива", чтобы позволить нам сделать struct
, который можно было бы комбинировать в соответствии с нашими требованиями к размеру. Я подозреваю, что это абсолютно безопасно для большинства разумных реализаций, но это законно в C, чтобы "перераспределить", если мы знаем в определенных ситуациях, что нам не нужны некоторые члены struct
?
Абстрактный пример
Скажем, у меня есть тип:
struct a {
bool data_is_x;
void * data;
size_t pos;
};
Если data_is_x
, то тип data
является типом, который должен использовать член pos
. В противном случае функции, которые работают с этим struct
, не будут нуждаться в элементе pos
для этой конкретной копии struct
. По существу, struct
содержит информацию о том, имеет ли он член pos
, и эта информация не будет изменена в течение жизни struct
(вне злого вреда, который все равно сломает что угодно). Можно ли сказать:
struct a *a = malloc(data_is_x ? sizeof(struct a) : offsetof(struct a, pos));
который будет выделять пространство для члена pos
только в случае необходимости? Или это нарушает ограничение на использование пространства замещения, которое слишком мало для указателя struct
, даже если вы никогда не используете этих членов?
Пример бетона
Мой случай использования в реальном мире немного связан; это здесь в основном, поэтому вы можете понять, почему я хочу это сделать:
typedef struct {
size_t size;
void * data;
size_t pos;
} mylist;
Код mylist_create
указывает, что для size > 0
, data
является массивом смежных данных, длина которых size
длинна (независимо от того, какой элемент может быть), но для size == 0
это текущий node двусвязного списка, содержащего элементы. Все функции, которые работают с mylist
, будут проверять, будет ли size == 0
. Если это так, они будут обрабатывать данные в виде связанного списка с "текущим" индексом, в зависимости от того, что указывает node data
. Если нет, они будут обрабатывать данные как массив с "текущим" индексом, хранящимся в pos
.
Теперь, если size == 0
нам не нужен элемент pos
, но если size > 0
, мы будем. Итак, мой вопрос: законно ли это сделать:
mylist *list = malloc(size ? sizeof(mylist) : offsetof(mylist, pos));
Если мы гарантируем (в случае штрафа undefined), что, пока size == 0
, мы никогда не будем пытаться (или должны) получить доступ к элементу pos
? Или он говорит где-то в стандарте, что UB даже подумывает об этом?