Преобразование 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
. Я совершаю очевидную ошибку?
@Blitz, 👍5
4 ответа
Лучший ответ:
Я предлагаю использовать союз:
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];
Я думаю, что последнее выражение выполняется исключительно как выражение 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
Просто для полноты картины, после публикации этого я нашел другой способ обойти это, но решение @Phataas намного элегантнее.
Используя функции ltoa
и atol
, преобразование long в массив char и наоборот можно сделать следующим образом:
char temp[10];
ltoa(669L,temp,10);
long result = atol(temp);
Это также намного более неэффективно., @uniquenamehere
Да, это так, но если вы хотите записать текстовый файл на SD-карту, это лучше, чем бинарный подход. В итоге я использовал комбинацию преобразования байтов с объединением и версию ltoa для печати в файлы журнала., @Blitz
char text[5];
long number = 1234;
sprintf(text,"%d",number);
long
может состоять более чем из 5 десятичных цифр и должен быть преобразован с использованием формата "%ld"., @DataFiddler
Пожалуйста, разверните свой ответ и объясните, почему вы считаете, что ваш код правильный., @Greenonline
- Как объявить массив переменного размера (глобально)
- Получение имени перечисления из экземпляра перечисления
- Объявленная переменная внутри void setup не видится в void loop
- Преимущества глобальных переменных перед статическими членами класса?
- Глобальная переменная не изменяется, когда значение задано в логической функции
- как «пропустить» один параметр метода со значением по умолчанию, позволяя ему использовать значение по умолчанию, но изменять параметры после него
- Как улучшить этот Код? (или как передать строку Char в функцию, чтобы она вела себя как переменная)
- Как я могу заставить условные операторы работать с логическим значением (true/false), чтобы включать и выключать синие светодиоды
Спасибо, это сработало отлично (для длинных, а не для поплавков). Можете ли вы дать мне ссылку на документацию для «союза»?, @Blitz
@LordT: я не знаю, почему я использовал float в качестве примера, я, должно быть, неправильно прочитал. У меня нет ссылки на страницу «документации», но это учебник/пример, который я считаю хорошим: http://www.tutorialspoint.com/cprogramming/c_unions.htm, @uniquenamehere