2013-07-26 48 views
5

Xin chào Tôi đang cố gắng đọc một mảng byte vào một cấu trúc và các byte sắp ra theo thứ tự ngược lại (theo cách tôi mong đợi). Ai đó có thể giúp tôi hiểu điều gì đang xảy ra không?cấu trúc c và thiết lập byte/đặt hàng

unsigned char buf[] = { 
0x11, 0x22, 0x33, 0x44, 
0x55, 0x66, 0x77, 0x88, 
0x99, 0xaa, 0xbb, 0xcc 
}; 


typedef struct mystruct { 
uint16_t var1; 
uint16_t var2; 
uint32_t var3; 
uint32_t var4; 
} something; 


int main(int argc,char **argv){ 

    printf("sizeof buf: %lu %d \n",sizeof(buf),sizeof(something)); 
    something *st = (something*)&(buf[0]); 
    #define pr(a) printf(#a" %x\n",a) 
    pr(st->var1); 
    pr(st->var2); 
    pr(st->var3); 
    pr(st->var4); 

    return(0); 
} 

Output:

sizeof buf: 12 12 
st->var1 2211 
st->var2 4433 
st->var3 88776655 
st->var4 ccbbaa99 

Tôi đã chờ đợi một cái gì đó như: st-> var1 1122

Việc làm này cũng dường như đầu ra điều tương tự?

memcpy(&st->var1,buf,2); 
pr(st->var1); 

đầu ra: st-> var1 2211

x86/Linux server, gcc phiên bản 4.5.3 (nếu điều đó giúp)

Nhờ sự giúp đỡ của bạn.

+2

Bạn có thể muốn đọc về tính xác thực.Bạn có thể làm điều này ở đây http://en.wikipedia.org/wiki/Endianness chẳng hạn. – alk

Trả lời

9

Nếu bạn đọc khoảng endianness, bạn sẽ thấy rằng có hai cách lưu trữ dữ liệu dài hơn một byte trong bộ nhớ.

Đối với các hệ thống lớn nhất (như ARM), giá trị số nguyên 0x1122 được lưu trữ trong bộ nhớ dưới dạng (từ địa chỉ thấp hơn đến cao hơn) 0x11 0x22. Trên một hệ thống nhỏ gọn (như x86), nó được lưu trữ là 0x22 0x11.

Khi dữ liệu của bạn trong mảng được lưu trữ "lớn cuối cùng", bạn sẽ nhận được thứ tự byte đối diện với những gì bạn mong đợi trên một hệ thống nhỏ như bạn.

+1

Ngoài ra còn có một vấn đề bí mật nghiêm ngặt. –

3

Khi những người khác đã chỉ ra vấn đề quan sát chính của bạn là một trong số edianness.

phương pháp của bạn để truy cập vào buf là hành vi không xác định vì nó vi phạm strict aliasing quy tắc ở đây theo loại punning đây:

something *st = (something*)&(buf[0]); 

Nếu tôi xây dựng mã này vào sử dụng gcc sử dụng các đối số sau đây:

-O3 --Wstrict-aliasing=2 

Tôi nhận được cảnh báo sau:

main.cpp:22:4: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing] 
    something *st = (something*)&(buf[0]); 
    ^

Tôi hiện đang sử dụng phiên bản 4.8. Phần có liên quan từ số C11 draft standard bao gồm các quy tắc bí danh là 6.5/7.

1

Như Joachim và Shafix đã nói, bạn có thể có vấn đề với đệm và endianness, nhưng nếu bạn có thể tận dụng #pragma pack mã này nên làm việc (swap byte khi little endian)

#include <stdio.h> 
#include <stdint.h> 

unsigned char buf[] = { 
    0x11, 0x22, 0x33, 0x44, 
    0x55, 0x66, 0x77, 0x88, 
    0x99, 0xaa, 0xbb, 0xcc 
}; 

typedef struct mystruct { 
    uint16_t var1; 
    uint16_t var2; 
    uint32_t var3; 
    uint32_t var4; 
} something; 

static uint16_t swap16(uint16_t val) 
{ 
    return ((val >> 8) & 0xFF) | ((val << 8) & 0xFF00); 
} 

static uint32_t swap32(uint32_t val) 
{ 
    uint16_t v1 = swap16((uint16_t) val); 
    uint16_t v2 = swap16((uint16_t) (val >> 16)); 
    return (v1 << 16) | (v2); 
} 

int main(void) 
{ 
    printf("sizeof buf: %zu %zu \n", sizeof(buf), sizeof(something)); 
    something *st = (something*)&(buf[0]); 

    #define pr(a) printf(#a" %x\n", a) 

#if __BYTE_ORDER == __LITTLE_ENDIAN 
    st->var1 = swap16(st->var1); 
    st->var2 = swap16(st->var2); 
    st->var3 = swap32(st->var3); 
    st->var4 = swap32(st->var4); 
#endif 

    pr(st->var1); 
    pr(st->var2); 
    pr(st->var3); 
    pr(st->var4); 

    return(0); 
} 

EDIT:

#pragma pack sẽ khiến trình xử lý trước loại bỏ căn chỉnh của các thành viên cấu trúc và do đó không chèn byte đệm, bạn có thể xác định cấu trúc của mình như sau:

#pragma pack(push, 1) // exact fit - no padding 
typedef struct mystruct { 
    uint16_t var1; 
    uint16_t var2; 
    uint32_t var3; 
    uint32_t var4; 
} something; 
#pragma pack(pop) //back to whatever the previous packing mode was 
+0

Phiên bản này vẫn có cùng một vấn đề bí danh nghiêm ngặt mà mã ban đầu có. –

+0

Bạn cũng có thể sử dụng các hàm 'ntohs' và' ntohl' của POSIX. – Useless

+0

@ShafikYaghmour, _if bạn có thể sử dụng '#pragma pack'_ –

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