Преобразование long в массив символов и обратно

Я пытаюсь сохранить состояние в регистраторе данных. Я могу нормально читать/писать на SD, но я не могу правильно прочитать/записать значение long - я построил его для преобразования в массив символов и обратно.

На данный момент моей лучшей попыткой было

long temp = 1418172669L;
unsigned char buf[4];
buf[0] = temp         & 0xFF;
buf[1] = (temp >>  8) & 0xFF;
buf[2] = (temp >> 16) & 0xFF;
buf[3] = (temp >> 24) & 0xFF;

long  l = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);

Но l сильно отличается от temp — в настоящее время вывод равен -26371. Я совершаю очевидную ошибку?

, 👍5


4 ответа


Лучший ответ:

9

Я предлагаю использовать союз:

union {
    char myByte[4];
    long mylong;
} foo;

Char в Long:

Тогда вы можете просто добавить байты:

foo myUnion;
myUnion.myByte[0] = buf[0];
myUnion.myByte[1] = buf[1];
myUnion.myByte[2] = buf[2];
myUnion.myByte[3] = buf[3];

Тогда вы можете получить доступ к длинному как:

myUnion.myLong;

Длинный поиск:

То же самое, если вы хотите перейти от массива long к массиву char:

foo myUnion
myUnion.myLong = 1234L;

Для доступа к байтам:

myUnion.myByte[0];
myUnion.myByte[1];
myUnion.myByte[2];
myUnion.myByte[3];
,

Спасибо, это сработало отлично (для длинных, а не для поплавков). Можете ли вы дать мне ссылку на документацию для «союза»?, @Blitz

@LordT: я не знаю, почему я использовал float в качестве примера, я, должно быть, неправильно прочитал. У меня нет ссылки на страницу «документации», но это учебник/пример, который я считаю хорошим: http://www.tutorialspoint.com/cprogramming/c_unions.htm, @uniquenamehere


1

Я думаю, что последнее выражение выполняется исключительно как выражение int и преобразуется в long только в конце, т.е. перед присваиванием l .

long  l = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);

Здесь компилятор вычисляет buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24) только как int.

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

long  l = buf[0] | (buf[1] << 8L) | (buf[2] << 16L) | (buf[3] << 24L);

Этого должно быть достаточно, чтобы компилятор выполнил всю операцию как long без потери точности.

,

Извините, даже с неявным длинным результатом будет -26371., @Blitz


0

Просто для полноты картины, после публикации этого я нашел другой способ обойти это, но решение @Phataas намного элегантнее. Используя функции ltoa и atol, преобразование long в массив char и наоборот можно сделать следующим образом:

char temp[10];
ltoa(669L,temp,10);
long result = atol(temp);
,

Это также намного более неэффективно., @uniquenamehere

Да, это так, но если вы хотите записать текстовый файл на SD-карту, это лучше, чем бинарный подход. В итоге я использовал комбинацию преобразования байтов с объединением и версию ltoa для печати в файлы журнала., @Blitz


-1
char text[5];
long number = 1234;
sprintf(text,"%d",number);
,

long может состоять более чем из 5 десятичных цифр и должен быть преобразован с использованием формата "%ld"., @DataFiddler

Пожалуйста, разверните свой ответ и объясните, почему вы считаете, что ваш код правильный., @Greenonline