Критически важно, хотите ли вы, чтобы файл был переносимым, или просто код.
Если вы когда-либо собираетесь читать данные обратно в одной и той же реализации C (и это означает, что с одинаковыми значениями для любых параметров компилятора, которые каким-либо образом влияют на разметку структуры), используя одно и то же определение структуры, тогда код переносимый. Это может быть плохой идеей по другим причинам: сложность изменения структуры, и теоретически могут возникнуть угрозы безопасности при выгрузке байтов заполнения на диск или байтов после любого NUL-терминатора в этом массиве символов. Они могут содержать информацию, которую вы никогда не намеревались сохранить. Тем не менее, ОС делает это все время в файле подкачки, ну и что, но попробуйте использовать это оправдание, когда пользователи замечают, что ваш формат документа не всегда удаляет данные, которые они считают удаленными, и просто отправляют их по электронной почте репортер.
Если файл нужно передавать между разными платформами, то это довольно плохая идея, потому что вы в конечном итоге случайно определяете формат файла как что-то вроде «что бы MSVC на Win32 не записывал». Это может оказаться довольно неудобным для чтения и записи на какой-либо другой платформе, и, конечно, код, который вы написали в первую очередь, не будет делать это при работе на другой платформе с несовместимым представлением структуры хранения.
рекомендуемый способ записи переносимых двоичных файлов в порядке предпочтения, вероятно, таков:
- Не. Используйте текстовый формат. Будьте готовы потерять некоторую точность в значениях с плавающей точкой.
- Используйте библиотеку, хотя здесь есть какое-то проклятье. Вы можете подумать, что ASN.1 выглядит хорошо, и это до тех пор, пока вам никогда не придется манипулировать этим материалом самостоятельно. Я предполагаю, что буфер протокола Google довольно хорош, но я никогда не использовал его сам.
- Определите довольно простой двоичный формат с точки зрения того, что означает каждый
unsigned char
в свою очередь. Это хорошо для символов [*] и других целых чисел, но становится немного хитрым для типов с плавающей точкой. «Это представление с прямым порядком байтов в формате IEEE-754», если все целевые платформы используют плавающие объекты IEEE, все будет в порядке. Что я ожидаю, что они делают, но вы должны сделать ставку на это. Затем соберите эту последовательность символов для записи и интерпретируйте ее для чтения: если вам «повезло», то на данной платформе вы можете написать определение структуры, которое точно соответствует ей, и использовать этот прием. В противном случае делайте любые манипуляции с байтами, которые вам нужны. Если вы хотите быть действительно переносимым, будьте осторожны, чтобы не использовать int
во всем коде для представления значения, взятого из bar
, потому что если вы сделаете это на какой-то платформе, где int
равен 16 битам, это не будет поместиться. Вместо этого используйте long
или int_least32_t
или что-то еще, и проверьте границы при записи. Или используйте uint32_t
и дайте ему завернуться.
[*] До тех пор, пока вы не нажмете на машину EBCDIC. Не то чтобы кто-то серьезно ожидал, что ваши файлы будут переносимы на компьютер, на котором простые текстовые файлы тоже не переносимы.