字节对齐不同造成结构体成员赋值失败

我们知道,C编译器在编译32位机目标代码时,默认将变量存储的地址按照4字节进行对齐。

在使用结构体时,由于字节对齐的原因可能会造成存储空间的浪费

例如:

struct AA{

    char a;

    int b;

    char c; 

}aa

结果,sizeof(aa)=12。成员a与b之间空出了3个空字节,成员c也后也空出了3个字节。


这个时候虽然内存空间有些浪费,但是并不会误导程序员进行编码。如果和联合体一起使用,就可能会造成一定的误解

例如

struct AA{
    union{
    struct{
  char Byte0;
     char Byte1;
     char Byte2;
     char Byte3;
  };
    int data;
 }
}aa

此处本来想将 Byte0 -Byte3作为 data的4个字节的重名以便对data的其中任意8bit进行操作。但是由于四字节对齐的原因只有Byte0是data的第0字节,Byte1-Byte3每一个成员都向后偏移了四个字节。

为了达到预期的效果,可以使用#pragma pack(n) 对编译器进行字节对齐设置。

#pragma pack(1)//按照1字节进行对齐
struct AA{
    union{
    struct{
  char Byte0;
     char Byte1;
     char Byte2;
     char Byte3;
  };
    int data;
 }
}aa
#pragma pack()//取消对齐设置
这样就可以达到预想的效果,使用Byte0-Byte3对data的每个字节进行单独的操作。

但是今天,由于我在使用#pragma pack() 指令犯了错误,产生了结构体成员赋值失败的情况。
情况如下:
文件a

struct AA{

    char a;

    char b;

    char c; 

}aa


文件b
#pragma pack(1)//按照1字节进行对齐
struct _cc{
    union{
    struct{
  char Byte0;
     char Byte1;
     char Byte2;
     char Byte3;
  };
    int data;
 }
}cc
 aa.b = 0x02;//此处给成员b赋值失败
#pragma pack()//取消对齐设置

我在文件a中使用默认的对齐设置(4字节对齐),创建了结构体aa。然后aa作为全局变量在文件b中进行赋值。
但文件b由于cc结构体的需要设置了1字节对齐
对结构体aa成员的赋值语句放在了取消对齐设置之前,编译器在编译文件b时对变量aa.b按照1字节对齐进行了操作,所以成员b的偏移地址为1。而实际上在定义aa时,成员b的偏移地址为4(a与b之间插入了3个空字节)
所以赋值并没有成功,而是将0x02写入了aa.a 与aa.b中间的填充字节。
在仿真这段程序时,就出现了赋值不成功的奇怪现象。

那么应该如何解决这个问题呢?
那就是谨慎的使用#pragma pack(n)指令

将需要对齐的结构体声明放在#pragma pack(n) 与 #pragma pack()之间,其他的代码不要放在这里面,特别是对对齐设置不同的结构体进行访问的代码段。
文件b改为
#pragma pack(1)//按照1字节进行对齐
struct _cc{
    union{
    struct{
  char Byte0;
     char Byte1;
     char Byte2;
     char Byte3;
  };
    int data;
 }
}cc
#pragma pack()//取消对齐设置
 aa.b = 0x02;//此处给成员b赋值成功

你可能感兴趣的:(嵌入式C)