Работа с различными архитектурами при загрузке данных с помощью stdio


Я хочу прочитать некоторые данные из файла. Скажем целое число:

fread(&var1, 4, 1, f);

Где var1-целое число. Но потом я подумал, что это небезопасно, так как нет никакой гарантии, что целое число имеет длину 4 байта. (Я игнорирую другие вопросы, такие как феоф и феррор, ради этого вопроса).

Я также вскоре понял, что есть еще больше проблем, чем просто размер int, таких как конечность системы, и, вероятно, другие, о которых я даже не думал от.

Итак, как лучше всего обеспечить правильную интерпретацию ваших данных, которые Вы читаете? До сих пор единственное, что я могу придумать, это просто хранить данные как текст, а не как двоичные данные, читать в тексте и преобразовывать его во время выполнения. Я бы предположил, что независимо от решения, если вы хотите убедиться, что оно портативно, оно всегда будет включать в себя какую-то форму преобразования в любом случае.

Спасибо.

2 2

2 ответа:

Чтобы избежать проблемы размера, вы должны делать:

fread(&var1, sizeof(var1), 1, f);
Если вы обеспокоены тем, что размер int может варьироваться между платформой, которая записывает данные, и платформой, которая их читает, то у вас есть более фундаментальная проблема. В этом случае следует избегать использования int, short, и т.д., и использовать типы, определенные в <stdint.h>, такие как int16_t, uint32_t.

Чтобы справиться с проблемами endianness, вы должны рассмотреть возможность написания вспомогательных функций, которые явно пишут / читают человека байты в известном порядке, например:

void write_uint32_t(uint8_t *buf, uint32_t x)
{
    buf[0] = (uint8_t)(x >> 0);
    buf[1] = (uint8_t)(x >> 8);
    buf[2] = (uint8_t)(x >> 16);
    buf[3] = (uint8_t)(x >> 24);
}

Все вышесказанное относится только к целочисленным типам. Для типов с плавающей запятой не существует идеального универсального решения.

Всегда используйте оператор sizeof() для получения размера типов. Никогда не полагайтесь на жестко закодированные значения!