我已经编写了这段代码,我已经为两个不同的结构分配了一个无符号整数。实际上它们是相同的,但其中一个具有__attribute __((packed))。
#include
#include
struct st1{
unsigned char opcode[3];
unsigned int target;
}__attribute__((packed));
struct st2{
unsigned char opcode[3];
unsigned int target;
};
void proc(void* addr) {
struct st1* varst1 = (struct st1*)addr;
struct st2* varst2 = (struct st2*)addr;
printf("opcode in varst1: %c,%c, %c\n",varst1->opcode[0],varst1->opcode[1],varst1->opcode[2]);
printf("opcode in varst2: %c,%c,%c\n",varst2->opcode[0],varst2->opcode[1],varst2->opcode[2]);
printf("target in varst1: %d\n",varst1->target);
printf("target in varst2: %d\n",varst2->target);
};
int main(int argc,char* argv[]) {
unsigned int* var;
var =(unsigned int*) malloc(sizeof(unsigned int));
*var = 0x11334433;
proc((void*)var);
return 0;
}
输出结果为:
opcode in varst1: 3,D,3
opcode in varst2: 3,D,3
target in varst1: 17
target in varst2: 0
鉴于我正在存储这个号码 0x11334433 == 00010001001100110100010000110011
我想知道为什么这是我得到的输出。
答案 0 :(得分:3)
这与数据对齐有关。大多数编译器会将地址边界上的数据对齐,以帮助实现一般性能。因此,在第一种情况下,具有packed属性的struct,char [3]和int之间有一个额外的字节,用于在四字节边界上对齐int。在打包版本中,填充字节丢失。
byte : 0 1 2 3 4 5 6 7
st1 : opcode[0] opcode[1] opcode[2] padding |----int------|
st2 : opcode[0] opcode[1] opcode[2] |-------int--------|
您分配一个unsigned int并将其传递给函数:
byte : 0 1 2 3 4 5 6 7
alloc : |-----------int------------------| |---unallocated---|
st1 : opcode[0] opcode[1] opcode[2] padding |----int------|
st2 : opcode[0] opcode[1] opcode[2] |-------int--------|
如果你使用的是小端系统,那么最低的8位(最右边)存储在字节0(0x33),字节1有0x44,字节2有0x33,字节4有0x11。在st1结构中,int值映射到超出分配量末尾的内存,而st2版本int的最低字节映射到字节4,0x11。因此st1产生0,st2产生0x11。
很幸运,未分配的内存为零,并且您没有进行内存范围检查。在这种情况下写入st1和st2中的int可能会在最坏的情况下破坏内存,生成内存保护错误或什么都不做。它是未定义的,取决于内存管理器的运行时实现。
一般情况下,请避免使用void *
。
答案 1 :(得分:1)
您的字节如下所示:
00010001 00110011 01000100 00110011
虽然显然你的字节顺序是错误的,事实上它们是这样的:
00110011 01000100 00110011 00010001
如果您的结构被打包,那么前三个字节与操作码相关联,第四个字节是目标 - 这就是为什么压缩数组的目标数为17 - 0001001(二进制)。
解压缩的数组用零填充,这就是为什么varst2中的目标为零的原因。
答案 2 :(得分:0)
int根据处理器体系结构存储小端或大端 - 您不能依赖它按顺序进入struct的字段。
解压缩版本中的int目标超过了int的位置,因此它保持为0。