您好我正在尝试将字节数组读入结构中,并且字节以相反的顺序出现(以我预期的方式)。有人能帮我理解发生什么事吗?
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(如果有帮助)
感谢您的帮助。
答案 0 :(得分:9)
如果您阅读endianness,您会发现有两种方法可以在内存中存储长于一个字节的数据。
对于大端系统(如ARM),整数值0x1122
作为(从较低地址到较高地址)0x11 0x22
存储在内存中。在小端系统(如x86)上,它存储为0x22 0x11
。
由于数组中的数据存储为“big-endian”,因此您可以获得与您喜欢的小端系统相同的字节顺序。
答案 1 :(得分:3)
正如其他人指出你的主要可观察问题是edianness。
之一您访问buf
的方法是未定义的行为,因为此处违反strict aliasing规则类型为punning:
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
。
答案 2 :(得分:1)
正如Joachim和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