#c #tcp #hex #double #modbus
#c #tcp #шестнадцатеричный #двойной #modbus
Вопрос:
У меня проблема. У меня есть ответ MODBUS TCP, который имеет шестнадцатеричную кодировку следующим образом: 0 0 0 0 0 7 1 4 4 41 В8 66 64. Для пояснения: первые пять нулей являются спецификацией Modbus, 7 — это количество байтов, следующих за ним. 1 — это адрес клиента в сети Modbus и не имеет значения. первые 4 — это код функции, который используется. вторые 4 — это снова следующие числа байтов. Последние четыре байта — это шестнадцатеричный ответ, который должен быть преобразован в double. Массив, в котором это хранится, представляет собой массив символов без знака. Вот несколько примеров того, как я это пробовал. Вот первый пример:
value = (ibuf[9]<<24) (ibuf[10]<<16) (ibuf[11]<<8) ibuf[12];
Значение — это используемая двойная переменная, а ibuf — используемый массив символов.
Здесь второй:
for(i = 0; i < k; i )
{
if (i==0)
{
sprintf(ergebnis, "%x%x", ibuf[9], ibuf[10]);
}
else
{
//sprintf(buffer,"%x%x",ibuf[9 i i], ibuf[10 i i]);
//strcat( ergebnis, buffer );
sprintf(ergebnis, "0x41b451e8");
sscanf(ergebnis, "%l %lf ", amp;Value);
}
printf("Ergebnis %sn", ergebnis);
}
Здесь я использовал фиксированное значение, но проблема всегда заключается в преобразовании из шестнадцатеричного в double.
Я рад любой помощи, которую я мог получить.
Ответ №1:
Вы почти на месте. К сожалению, преобразование происходит автоматически во время продвижения — самый «простой» способ обойти это — разыменование приведения указателя с плавающей запятой для int , как так:
int ival = (ibuf[9]<<24) (ibuf[10]<<16) (ibuf[11]<<8) ibuf[12];
float fval = *(float*)amp;ival;
Для предоставленных данных это дает 23.049995 вместо 1.1026039e 009, который вы получаете в результате преобразования.
Редактировать:
Как указал Майк Сеймур в комментарии ниже, предпочтительный способ написать это:
float fval = *reinterpret_cast<float*>(amp;ival);
Обратите внимание, что вы не можете этого сделать:
float fval = reinterpret_cast<float>(ival);
Это вызовет ошибку (как показано здесь в VS2005):
error C2440: 'reinterpret_cast' : cannot convert from 'int' to 'float'
Комментарии:
1. Я бы предпочел видеть
reinterpret_cast
, а не приведение в стиле C, чтобы было понятнее, что преобразование является нестандартным, и сохранить постоянную корректность.
Ответ №2:
Я бы использовал побитовый оператор or для воссоздания значения с плавающей запятой.
unsigned int value = 0x00000000 | ibuf[9] << 24
| ibuf[10] << 16
| ibuf[11] << 8
| ibuf[12];
float floatValue = (float)value;
Этот код предполагает, что unsigned int имеет размер четыре байта на вашей платформе.
Комментарии:
1. прямое преобразование в виде float выполняет преобразование. Этот метод работает некорректно. Смотрите мой ответ.