Dalam jawaban ini , zwol membuat klaim ini:
Cara yang benar untuk mengkonversi dua byte data dari sumber eksternal menjadi integer bertanda 16-bit adalah dengan fungsi pembantu seperti ini:
#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;
}
Manakah dari fungsi di atas yang sesuai tergantung pada apakah array berisi representasi endian kecil atau besar. Endianness bukan masalah yang dipertanyakan di sini, saya bertanya-tanya mengapa zwol mengurangi 0x10000u
dari uint32_t
nilai yang dikonversi int32_t
.
Mengapa ini cara yang benar ?
Bagaimana cara menghindari perilaku yang ditentukan implementasi ketika mengkonversi ke tipe kembali?
Karena Anda dapat mengasumsikan representasi komplemen 2's, bagaimana gips sederhana ini gagal: return (uint16_t)val;
Apa yang salah dengan solusi naif ini:
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
tidak dapat direpresentasikan sebagai int16_t
, dan dalam pendekatan kedua 0xFFFFu
tidak dapat direpresentasikan sebagai int16_t
.
int16_t
didefinisikan, sehingga pendekatan naif tidak mudah dibawa-bawa.