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 0x10000udari uint32_tnilai 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
0xFFFF0001utidak dapat direpresentasikan sebagai int16_t, dan dalam pendekatan kedua 0xFFFFutidak dapat direpresentasikan sebagai int16_t.
int16_tdidefinisikan, sehingga pendekatan naif tidak mudah dibawa-bawa.