Платформо-независимое хранилище целых чисел со знаком - PullRequest
2 голосов
/ 26 октября 2011

Я хочу записать целочисленные значения со знаком в файл независимо от платформы.

Если бы они были без знака, я бы просто преобразовал их из порядка байтов хоста в LE (или BE) с помощью endian (3) семейство функций.

Хотя я не уверен, что делать со знаковыми целыми числами.Если я приведу их к значениям без знака, я потеряю знак, так как стандарт C не гарантирует, что

(int) ((unsigned) -1)) == -1

Другой вариант заключается в том, чтобы я приводил указатель к значению (т. Е. Переосмысливал последовательность байтовкак unsigned), но я не уверен, что преобразование порядка байтов после этого даст что-нибудь разумное.

Как правильно хранить независимое от платформы целочисленное хранение со знаком?

Обновление :

  • Я знаю, что на практике , почти во всех архитектурах используется представление с двумя дополнениями, так что я могу без потерь преобразовывать целые числа со знаком и без знака.Тем не менее, этот вопрос должен быть более теоретическим.

  • Просто выкатить мое собственное целочисленное представление (будь то сохранение десятичных букв в виде символов ascii или раздельное хранение знакового бита)конечно решение.Однако мне интересно, есть ли способ, который работает без полного отказа от собственного двоичного представления.

Ответы [ 6 ]

3 голосов
/ 26 октября 2011

Самое простое решение:

Для записи просто преобразуйте в unsigned и используйте функции преобразования в порядковый номер без знака.

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

uint32_t temp;
int32_t dest;
if (temp > INT32_MAX) dest = -(int32_t)(-temp-1)-1;
else dest = temp;

В качестве дополнительного бонуса, хороший компилятор в разумной системе (то есть система с двумя дополнениями, где реализация-определенное преобразование в unsigned является "правильным") сначала оптимизирует -(int32_t)(-temp-1)-1 до (int32_t)temp, а затем оптимизирует две ветви условного выражения, которые теперь оба содержат идентичный код, в один путь кода без ветви.

1 голос
/ 26 октября 2011

Используйте тот же подход, что и при отправке данных по сети.Преобразуйте ваши значения без знака или со знаком в big-endian и сохраните их, используя htonl().При чтении преобразуйте данные обратно в свой порядковый номер машины, используя ntohl().

Но, как всегда, вам нужно знать, были ли данные изначально подписаны или не подписаны.С небольшой последовательностью вы не можете знать наверняка.

1 голос
/ 26 октября 2011

Платформо-независимый способ?Если вы действительно хотите этого, вам следует подумать о том, чтобы записать его как текст, а не как двоичный файл (и с учетом того, что даже , что не является полностью независимым от платформы, так как вы можете захотеть переместить его изASCII для платформы EBCDIC).

Все зависит от того, насколько не зависит от платформы, какой вам нужна.C допускает три разных кодированных знака: два дополнения, одно дополнение и знак / величина.Но, безусловно, большинство машин будут использовать первый.

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

0 голосов
/ 26 октября 2011

Сохраните знак и абсолютное значение как 2 поля и рекомбинируйте их при обратном чтении.

Вы сказали, что уже знаете, как преобразовать в / из четко определенного порядка байтов, так что все этооставлено, чтобы определить знак (подсказка <0 может помочь здесь :-)), взять абсолютное значение (которое вы могли бы сделать в сочетании с определением, что это такое, или с помощью abs () или аналогичным. </p>

Примерно так:

if (num < 0) {
  negative = 1;
   num      = -num;
 } else {
   negative = 0
 }
write_value = htole32(num);
write(file, &negative, 1);
write(file, &write_value, 4);

В качестве оптимизации вы можете собрать биты знака для значений вместе и сохранить их в одном слове до абсолютных значений.

0 голосов
/ 26 октября 2011

Выведите 1-байтовый флаг (например, 0 = положительный, 1 = отрицательный).Если значение отрицательное, сделайте его положительным, а затем запишите значение в формате с прямым порядком байтов.Если вам не нравятся 0 и 1, вы можете использовать «+» и «-».

0 голосов
/ 26 октября 2011

Параметры:

  • Сохранение чисел в виде простого текста с использованием printf () - похожих функций для преобразования
  • Преобразование отрицательных чисел в знак + абсолютное значение, сохранение их как без знака с дополнительным битом знака
...