Gelen bu cevap , Zwol bu iddiayı yaptı:
İki bayt veriyi harici bir kaynaktan 16 bit işaretli tam sayıya dönüştürmenin doğru yolu aşağıdaki gibi yardımcı işlevlerdir:
#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;
}
Yukarıdaki işlevlerden hangisinin uygun olduğu, dizinin küçük bir endian mı yoksa büyük bir endian temsili içeriğine mi bağlıdır. Endian neden merak ediyorum, burada söz konu değil Zwol toplayıp çıkarmadan 0x10000u
gelen uint32_t
değere dönüştürülür int32_t
.
Neden doğru yol bu ?
Dönüş türüne dönüştürürken uygulama tanımlı davranışı nasıl önler?
2'nin tamamlayıcı temsilini varsayabildiğiniz için, bu daha basit yayın nasıl başarısız olur: return (uint16_t)val;
Bu saf çözümün nesi yanlış:
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
olarak temsil edilemez int16_t
ve ikinci yaklaşımda 0xFFFFu
olarak temsil edilemez int16_t
.
int16_t
uygulama tanımlıdır, bu yüzden saf yaklaşım taşınabilir değildir.