Определение рекурсивного объединения в C - PullRequest
0 голосов
/ 27 сентября 2018

Я хотел создать что-то вроде бинарного дерева поиска для сопоставления адресов с Page * с (за исключением того, что оно на самом деле было шестнадцатеричным, и адрес подразумевается самой структурой), поэтому:

typedef union Map Map;
union Map {
    Map (*ps)[16];
    Page *p;
};

Это логично (логически (объединение Map, содержащее либо указатель на Page, либо указатель на массив из 16 Map с), но ошибки gcc при объявлении ps с array type has incomplete element type, поэтомуЯ думаю, что этот вид рекурсивного определения не разрешен в C.

Есть ли способ сделать это без использования трюков, таких как псевдонимы указателей?

1 Ответ

0 голосов
/ 27 сентября 2018

C 2018 6.7.6.2 1 определяет ограничения для деклараторов массива.В нем говорится, частично:

Тип элемента не должен быть неполным или функциональным.

В Map (*ps)[16], (*ps)[16] представляет собой объявлений , как показано в грамматике в 6.7.6 1. Поскольку это декларатор массива, он подчиняется правилам в 6.7.6.2, и поэтому тип элемента должен быть завершен.Это верно, даже если объявленный типовой тип является указателем.

Как отмечено в комментарии, вы можете объявить Map *ps вместо этого.Если это неудовлетворительно, потому что тогда арифметика указателей на ps работает в единицах Map вместо Map [16], альтернативой может быть определение typedef struct Map16 Map16; перед объединением, затем Map16 *ps; внутри объединения, а затем struct Map16 { Map element[16]; } после объединения.Это заставит арифметику указателя на ps работать в нужных единицах (предположим, что реализация не дополняет структуру, что было бы необычно), хотя она и заставляет использовать дополнительный .element при обращении к элементам.

Рассматривая, почему Map *ps принимается, а Map (*ps)[16] нет, мы видим, что оба объявляют указатели на неполные типы, и поэтому их отличает не полнота указательного типа, а просто это правило в Cстандарт.Может случиться так, что правило в 6.7.6.2 1 могло быть изменено для разрешения Map (*ps)[16], так как не похоже, что компилятору требуется полная информация о указанном типе в этой точке.

...