Может кто-нибудь объяснить это определение структуры 'dirent' в Solaris? - PullRequest
6 голосов
/ 19 февраля 2009

Недавно я просматривал структуру 'dirent' (в dirent.h) и был немного озадачен ее определением.

ПРИМЕЧАНИЕ. Этот заголовочный файл взят с компьютера Solaris в моей школе.

<code>
typedef struct dirent {
    ino_t       d_ino;
    off_t       d_off;
    unsigned short  d_reclen;
    char        d_name[1];
} dirent_t;

В частности, поле d_name. Как это будет работать в операционной системе? Если вам нужно хранить строку с нулевым символом в конце, что хорошего в массиве одного символа? Я знаю, что вы можете получить адрес массива по его первому элементу, но я все еще в замешательстве. Очевидно, что-то происходит, но я не знаю что. В моей системе Fedora Linux дома это поле просто определяется как:

char d_name[256];

Теперь это имеет больше смысла по очевидным причинам. Может кто-нибудь объяснить, почему заголовочный файл Solaris определяет структуру так, как он это делает?

Ответы [ 4 ]

10 голосов
/ 19 февраля 2009

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

Удобно объявить член как имеющий размер 1, потому что легко определить, сколько памяти занято любой переменной dirent d:

sizeof(dirent) + strlen(d.d_name)

Использование размера 1 также препятствует получателю таких значений структуры пытаться сохранить в нем свои собственные имена вместо того, чтобы выделять свои собственные значения dirent. Используя определение Linux, разумно предположить, что любое имеющееся у вас значение dirent будет принимать строку из 255 символов, но Solaris не гарантирует, что в значениях dirent будет храниться больше символов, чем необходимо.

Я думаю, что C 99 ввел особый случай для последнего члена структуры. Структура может быть объявлена ​​так:

typedef struct dirent {
  ino_t d_ino;
  off_t d_off;
  unsigned short d_reclen;
  char d_name[];
} dirent_t;

Массив не имеет объявленного размера. Это известно как гибкий элемент массива . Он выполняет то же самое, что и версия Solaris, за исключением того, что нет иллюзии, что сама структура может содержать любое имя. Глядя на это, вы знаете, что это еще не все.

Используя "гибкую" декларацию, объем занятой памяти будет изменен следующим образом:

sizeof(dirent) + strlen(d.d_name) + 1

Это потому, что член гибкого массива не учитывает размер структуры.

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

5 голосов
/ 19 февраля 2009

Это шаблон, используемый в C для указания массива произвольной длины в конце структуры. Массивы в C не имеют встроенной проверки границ, поэтому, когда ваш код пытается получить доступ к строке, начинающейся с d_name, он будет продолжаться после конца структуры. При этом readdir() выделит достаточно памяти для хранения всей строки плюс завершающий ноль.

5 голосов
/ 19 февраля 2009

За структурой dirent сразу же следует в памяти блок памяти, содержащий оставшуюся часть имени, и эта память доступна через поле d_name.

1 голос
/ 19 февраля 2009

Для меня это выглядит как микрооптимизация. Имена, как правило, короткие, поэтому зачем выделять место, которое, как вы знаете, останется неиспользованным. Также Solaris может поддерживать имена длиннее 255 символов. Чтобы использовать такую ​​структуру, вы просто выделяете необходимое пространство и игнорируете предполагаемый размер массива.

...