Trong câu trả lời này , zwol đã đưa ra yêu cầu này:
Cách chính xác để chuyển đổi hai byte dữ liệu từ nguồn bên ngoài thành số nguyên có chữ ký 16 bit là với các hàm trợ giúp như thế này:
#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;
}
Hàm nào trong các hàm trên là phù hợp phụ thuộc vào việc mảng chứa một đại diện endian nhỏ hay đại diện endian lớn. Endianness không phải là vấn đề ở đây, tôi tự hỏi tại sao zwol trừ 0x10000u
khỏi uint32_t
giá trị được chuyển đổi thành int32_t
.
Tại sao đây là cách chính xác ?
Làm thế nào để tránh hành vi được xác định thực hiện khi chuyển đổi sang loại trả về?
Vì bạn có thể giả sử đại diện bổ sung của 2, nên diễn viên đơn giản hơn này sẽ thất bại như thế nào: return (uint16_t)val;
Có gì sai với giải pháp ngây thơ này:
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
không thể được biểu diễn dưới dạng int16_t
và trong cách tiếp cận thứ hai 0xFFFFu
không thể được biểu diễn dưới dạng int16_t
.
int16_t
được xác định theo triển khai, vì vậy cách tiếp cận ngây thơ không mang tính di động.