У меня есть немного проблемы в сценарии где:
while (read(dp->fd, (char *) &dirbuf, sizeof(dirbuf)) == sizeof(dirbuf)) { ... }
где dirbuf:
struct direct dirbuf {
ino_t d_ino; char d_name[DIRSIZ];
};
Как C знает для чтения в данных условно в нашу структуру? С чтением () Как, выравнивание нашего dirbuf соответствует отлично как символьный массив? так как чтение признает, что пустота * для ее второго аргумента, передавая структуру как бросок для обугливания * имеет очень мало смысла мне, как это обслуживает другие членские элементы правильно?
Я не уверен, задаю ли я даже этот вопрос правильно, я надеюсь, что кто-то может дешифровать мою проблему позади моей невменяемости и выручить меня.
Спасибо.
Он не читает и не выравнивает поля в структуре должным образом. Он просто берет общий размер структуры (из sizeof
) и начальный адрес (из & dirbuf
) и считывает в эту память без учета объявления структуры.
Предполагается, что все, что было в файле, было уже правильно выровнено, чтобы соответствовать структуре.
Приведение (char *)
используется только для остановки компилятора. (void *)
подойдет так же. Или вообще без приведения, поскольку компилятор преобразует тип указателя в void * без приведения.
Это должно быть дань устаревшим версиям языка C, в которых не было типа void *
, а вместо них использовался char *
. Если вы используете неархаичный компилятор и параметр действительно равен void *
, нет необходимости приводить что-либо к char *
(и нет необходимости приводить что-либо к void *
либо)
read(dp->fd, &dirbuf, sizeof(dirbuf))
И C не знает, и ему не нужно знать, как считывать данные в вашу конкретную структуру. Когда вы делаете что-то подобное, двоичные данные из файла вслепую считываются в необработанную память, занимаемую вашим объектом dirbuf
. Если макет этих двоичных данных правильный (например, если файл был создан путем записи той же структуры таким же образом), тогда все будет правильно выровнено и все автоматически встанет на свои места.
Обратите внимание: если вы не работаете с чем-то, на что распространяется очень строгая спецификация, такие простые методы двоичной записи / чтения можно использовать только в одном сеансе одной и той же программы или, возможно, между разными сеансами одной и той же версии. программы на той же платформе. Как только вы начнете иметь дело с разными платформами и / или разными версиями кода на одной платформе, все может легко развалиться, как только изменится необработанная структура памяти данных.
Приведение буферов к char *
- это устаревший шаблон кода, который часто встречается. Он использовался так часто, что его все еще набирают сегодня, спустя долгое время после того, как в нем перестала быть необходимость.
В какой-то момент не было типа void
, поэтому API вроде read (2)
объявлял бы параметр буфера как char *
, и все вызывающие преобразовать свои данные в char *
.
Но читать (2)
было пустотой *
долгое, долгое время. Прошло столько времени, когда на месте вызова была необходимость иметь какую-либо гипсовую повязку.
Однако старый код все еще существует, люди все еще читают его, а затем увековечивают шаблон проектирования.
Это не вредит.
Что касается непрерывных данных, происходит одно из двух. Либо структура данных и тип предназначены для плотного размещения на большинстве или всех вероятных машинах, либо аналогичный оператор использовался для записи данных в первую очередь, поэтому байты заполнения не имеют значения, если файл данных не должен быть перемещен между разрозненными архитектурами.