In dieser Antwort machte zwol diese Behauptung:
Die korrekte Methode zum Konvertieren von zwei Datenbytes von einer externen Quelle in eine 16-Bit-Ganzzahl mit Vorzeichen besteht in folgenden Hilfsfunktionen:
#include <stdint.h>
int16_t be16_to_cpu_signed(const uint8_t data[static 2]) {
uint32_t val = (((uint32_t)data[0]) << 8) |
(((uint32_t)data[1]) << 0);
return ((int32_t) val) - 0x10000u;
}
int16_t le16_to_cpu_signed(const uint8_t data[static 2]) {
uint32_t val = (((uint32_t)data[0]) << 0) |
(((uint32_t)data[1]) << 8);
return ((int32_t) val) - 0x10000u;
}
Welche der oben genannten Funktionen geeignet ist, hängt davon ab, ob das Array eine Little-Endian- oder eine Big-Endian-Darstellung enthält. Endianness ist hier nicht das fragliche Thema, ich frage mich, warum zwol0x10000u
von dem uint32_t
umgerechneten Wert subtrahiert int32_t
.
Warum ist das der richtige Weg ?
Wie wird das implementierungsdefinierte Verhalten bei der Konvertierung in den Rückgabetyp vermieden?
Wie würde diese einfachere Besetzung scheitern, da Sie die Komplementdarstellung von 2 annehmen können: return (uint16_t)val;
Was ist los mit dieser naiven Lösung:
int16_t le16_to_cpu_signed(const uint8_t data[static 2]) {
return (uint16_t)data[0] | ((uint16_t)data[1] << 8);
}
int16_t
0xFFFF0001u
kann nicht als dargestellt werden int16_t
, und im zweiten Ansatz 0xFFFFu
kann nicht als dargestellt werden int16_t
.
int16_t
ist implementierungsdefiniert, sodass der naive Ansatz nicht portierbar ist.