2015-07-24 19 views
6

Tôi đã cấu trúc sau đây và "getter" hàm trả về a cast đến một số nguyên unsigned:Đúc các loại con trỏ trên kiến ​​trúc khác nhau

struct s { 
    uint32_t a; 
}; 

void get_a(struct s *st, unsigned *ret) 
{ 
    *ret = (unsigned)st->a; 
} 

Các mã sau đây được điều hành:

struct s st; 
uint16_t x; 

st.a = 1; 
get_a(&st, (unsigned *)&x); 

Và đối với x86_64, i686, armv7hl, ppc64le và các kiến ​​trúc khác x == 1, nhưng đối với ppc64 x == 0. Tại sao điều này? Little- so với big-endian?

+0

Đặt thành 0x12345678. Các máy nhỏ gọn sẽ trả về 0x5678, lớn nhất là 0x1234. Để duy trì hành vi tương tự trên tất cả các máy sử dụng các hàm htonl/htons/ntohl/ntohs. – nsilent22

Trả lời

5

Vấn đề là bạn có:

uint16_t x; 

nhưng sau đó bạn cố gắng để viết thư cho rằng vị trí bộ nhớ như thể nó là vị trí của unsigned.

Nếu bạn đang sử dụng hệ thống nơi unsigneduint16_t cùng loại, điều này là tốt. Nhưng trên các hệ thống khác, chẳng hạn như hệ thống bạn đã sử dụng cho mẫu mã của mình, bạn đang gặp sự cố.

Trước hết, điều này gây ra undefined behaviour do vi phạm strict aliasing rule. Các biến loại uint16_t chỉ có thể được ghi qua các loại giá trị uint16_t hoặc loại ký tự.

Nhưng ngay cả khi nó không vi phạm nghiêm ngặt răng cưa, bạn vẫn sẽ gây ra UB bằng cách viết bên ngoài các giới hạn của x. Có lẽ, bạn đang viết 4 hoặc 8 byte vào một vị trí bộ nhớ 2 byte, do đó, nó sẽ tràn bộ đệm.

Cũng có thể có UB nếu x không chính xác aligned cho unsigned.

+0

Tôi nghĩ rằng nó cũng đáng nói đến rằng endianness không có gì để làm trong trường hợp này. – edmz

+1

@black nó loại nào: * nếu * tất cả UB trong đoạn mã không tạo ra ma quỷ lần này, chúng ta có thể mong đợi rằng bit '1' được viết xuất hiện bên trong' x' hoặc bên ngoài 'x' tùy thuộc vào trên hệ thống endianness –

+1

Bài học kinh nghiệm: Không đúc con trỏ, hoặc ít nhất là rất cẩn thận với những gì bạn đang làm. Có chủ yếu là một giải pháp khác. Ở đây một biến được đánh dấu 'unsigned' tạm thời sẽ xóa sạch mọi sự không chắc chắn. – alk

Các vấn đề liên quan