2013-07-26 49 views
5

嗨我想读取一个字节数组到一个结构和字节出来的顺序相反(我的预期)。有人可以帮助我了解发生了什么事吗?c结构和字节设置/订购

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); 
} 

输出:

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

我期待这样的: ST-> VAR1 1122

这样做似乎也是输出同样的事情?

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

输出: ST-> VAR1 2211

的x86/Linux服务器,gcc版本4.5.3(是否有帮助)

感谢您的帮助。

+2

您可能想阅读关于排序。例如,你可以在http://en.wikipedia.org/wiki/Endianness处这样做。 – alk

回答

9

如果您阅读了关于endianness,您会看到有两种方式将数据存储超过一个字节在内存中。

对于大端系统(如ARM),整数值0x1122作为(从较低地址到较高地址)0x11 0x22存储在内存中。在一个小端系统(如x86)上,其存储为0x22 0x11

由于数组中的数据存储为“big-endian”,因此您会得到与您期望的小端系统相反的字节顺序。

+1

还有一个严格的别名问题。 –

3

正如其他人指出你的主要可观察问题是edianness之一。

您的访问buf方法是不确定的行为,因为在这里违反strict aliasing规则的类型夯实这里:

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

如果我建在使用gcc使用以下参数验证码:

-O3 --Wstrict-aliasing=2 

我收到以下警告:

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

我目前使用的版本是4.8。覆盖别名规则的C11 draft standard中的相关部分是6.5/7

1

正如约阿希姆和Shafix说,你可以有填充和字节顺序的问题,但如果你可以利用#pragma pack此代码应工作(交换字节时小端)

#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); 
} 

编辑:

#pragma pack将导致预处理器丢弃该结构构件,因此没有填充字节的预先确定的取向将被插入,可以定义结构如下:

#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

该版本仍然具有与原始代码相同的严格别名问题。 –

+0

您也可以使用POSIX'ntohs'和'ntohl'功能。 – Useless

+0

@ShafikYaghmour,_if你可以使用'#pragma pack'_ –