Как элегантно читать/записывать поле структуры как число с плавающей запятой с прямым порядком байтов?C++

Программы на C++. Форум разработчиков
Ответить Пред. темаСлед. тема
Anonymous
 Как элегантно читать/записывать поле структуры как число с плавающей запятой с прямым порядком байтов?

Сообщение Anonymous »

Я написал код, который перехватывает пакеты данных и изменяет их. 4 байта в пакетах данных представляют собой значение с плавающей запятой, но в обратном порядке байтов (little-endian). И это создает для меня много проблем. Позвольте мне объяснить на упрощенном фрагменте кода:

Код: Выделить всё

#include 

typedef struct {
uint8_t start_seq[2];
uint8_t body_size;
uint8_t type;
uint8_t unknown;
uint8_t entity_id;
uint8_t reserved[3];
float value;
uint8_t end_seq[2];
} Packet;

void printRawPacket(const char* message, const uint8_t* packet, size_t length) {
Serial.print(message);
for (int i = 0; i < length; i++) {
Serial.printf("%02X ", packet[i]);
}
Serial.println();
}

// Packet interceptor function
void handlePacket(uint8_t* raw_packet, size_t length) {
// Create a pointer to the packet structure
Packet* packet = (Packet*)raw_packet;

printRawPacket("Original bytes: ", raw_packet, sizeof(raw_packet));
// Correctly Prints: "Original bytes: BE EF 08 03 00 09 00 00 00 00 00 C0 40 EF BE"

// Access the float value without creating a copy of the 4 bytes
Serial.print("Original value: ");
Serial.println(packet->value);
// Incorrectly prints a random value or "ovf" instead of 6.00

// Modify the float value without creating a copy of the 4 bytes
packet->value = -120.0f; // little endian would be 00 00 F0 C2; big endian would be C2 F0 00 00
Serial.print("Modified value: ");
Serial.println(packet->value); // Prints -120.0 correctly

printRawPacket("Modified bytes: ", raw_packet, sizeof(raw_packet));
// Incorrectly Prints: "Modified bytes: BE EF 08 03 00 09 00 00 00 00 00 C0 00 00 F0"
// Showing the float value was not stored correctly and the footer was overwritten
// Expected output would have been: "Modified bytes: BE EF 08 03 00 09 00 00 00 00 00 00 00 F0 C2 EF BE"
}

void setup() {
Serial.begin(115200);

// Example packet
uint8_t raw_packet[] = {
// ------ HEADER ------
0xBE, 0xEF, // start sequence
0x08,       // body size uint8_t
0x03,       // type uint8_t
0x00,       // unknown
// ------ HEADER ------

// ------ BODY ------
0x09,                   // entity id uint8_t
0x00, 0x00, 0x00,       // reserved
0x00, 0x00, 0xC0, 0x40, // value (float, little-endian) // 6.0f
// ------ BODY ------

// ------ FOOTER ------
0xEF, 0xBE // end sequence
// ------ FOOTER ------
};

handlePacket(raw_packet, sizeof(raw_packet));
}

void loop() {
// Nothing to do here
}
Как объяснено в комментариях, это не работает на нескольких уровнях.
Я могу легко обойти эту проблему, сделав поле значения uint8_t value[4], а затем используя функцию получения и установки, например:

Код: Выделить всё

typedef struct {
uint8_t start_seq[2];
uint8_t body_size;
uint8_t type;
uint8_t unknown;
uint8_t entity_id;
uint8_t reserved[3];
uint8_t value[4];
uint8_t end_seq[2];

// Function to get the float value from the raw packet in little-endian format
float getFloatLeValue() const {
// reverse byte order and return as float
uint32_t temp = (value[3] > 16) & 0xFF;
value[3] = (temp >> 24) & 0xFF;
}
} Packet;
Но это кажется слишком сложным и сложным, когда все, что я хочу сделать, это интерпретировать 4 байта в обратном порядке.
Есть ли более простой и элегантный способ ?
(Я пишу свой код на C++ на PlatformIO для ESP32 с использованием Arduino Framework.)

Подробнее здесь: https://stackoverflow.com/questions/787 ... dian-float
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C++»