C语言中的数据对齐

数据对齐的目的,是用空间换时间,提高效率.

对齐本身并不难理解,但是有这么一个古怪的命令#pragma pack()存在,它可以人为指定按几个字节来对齐.有了这个命令,就让情况变得更加复杂了.

网上有很多#pragma pack()命令的使用方法总结,但我不认为这个命令是必要的,应该尽量避免使用.

如果你的代码里使用了#pragma pack(),会导致sizeof()取得预料外的值,导致程序出错.这个错误并不容易发现.

#pragma pack()能让你的内存存储变紧凑,但会让sizeof()变得诡异,值得么?不值.

(也许写程序传输协议时需要#pragma pack()来防止结构体中出现空洞?很牵强,我不认为这是必须的.)

干脆,抛开#pragma pack()命令,简简单单来理解数据对齐吧.

对齐表明了数据在内存中的存放方式,内存的最小单位是1字节,对齐长度为1说明数据可以存储在任何内存地址.对齐长度为2说明只能存放在能被2整除的内存地址.对齐长度是4只能存放在能被4整除的内存地址.对齐长度只能是2的幂,也就是1,2,4,8,16...

数据对齐只会影响到结构体(或联合),归纳起来有如下两个规则:

1.结构体外的数据类型,它们按照自身大小来对齐.比如char型对齐长度是1,int型对齐长度是4,double型对齐长度是8.(32位系统下一般是这样).

2.结构体本身也有一个对齐长度,这个值是内部成员中自身对齐长度最大的那个值.结构体需按自身对齐长度对齐,换句话说,结构体大小必须是本身对齐长度的整数倍.

根据上面两条,你就会算结构体的大小了.

例1:

struct A
{
    char a;
    long b;
    char c;
    double d;
};

分析:

sizeof(struct A)=24.a占一个字节,b对齐长度是4,所以a后面补三个字节的洞后再存b.紧跟着是c占一个字节,d的对齐长度是8,所以c后面补7个字节的洞后再存d.共24字节.

struct A本身的对齐长度是8.

例2:

struct B
{
    char a;
    char b;
    long c;
    double d;
};

 分析:

sizeof(struct B)=16.a占一个字节,b也占一个字节.c对齐长度是4,所以b后补两个字节洞后存c.d对齐长度是8,前面abc加起来恰好8字节,所以d可以紧跟c存放.共16字节.

struct B本身的对齐长度是8.

例3:

struct C
{
  char a[123];
  int b;
  float c;
  double d;
};

分析:

sizeof(struct C)=144.a占123个字节,后补一个字节洞后存4字节的b,此时地址仍然能被4整除,所以紧跟着存4字节的c,目前总长度132,补4字节洞后存入8字节的d.总大小144字节.

等等!有疑问!

char a[123]的对齐长度是1还是123?是1.数组并非一种数据类型,这个数组的数据类型是char,char的对齐长度是1.

所以,struct C的自身对齐长度是8,144是8的整数倍,没问题.

例4:

struct D
{
  struct x
  {
    char a;
    int b;
    float c;
   }X;
  int d;
  char e;
};

分析:

sizeof(struct D)=20.先看struct x.a一个字节,补三个字节洞后跟4字节的b,之后是4字节的c.X的长度是12字节.struct x的自身对齐长度是4.再看struct D,X12字节,后跟4字节的d,之后是1个字节的e.struct D的自身对其长度是4(不是12,想一想吧).所以e后面要补三个字节洞.总长度是12+4+4=20.

例5:

struct E
{
  union y
  {
    char a;
    double b;
    int c;
  }Y;
  int d;
  double e;
};

分析:

sizeof(struct E)=24.Y是一个联合,联合的特点是它会占用跟最大的内部成员相同的空间,double最大,所以union y的对齐长度是8.之后是4字节的d.8+4=12为了对齐后面是8字节的e,d后面要补4字节的洞.所以总长度是8+8+8=24.

数据对齐基本就讲完了,描述不是特别清楚,还请见谅.

在网上,看到有人提出了如下的疑问,请试试看能否替他解答一下呢?

Struct A
{
  char a,b;
  char arr[5];
}
//这个sizeof(A)=7.。1+1+5 = 7.。对齐单位为1字节。这个可以理解。

Struct B
{
  int a,b;
  char arr[5];
}
//这个sizeof(B) = 16.. 是怎么对齐的? 数组占了8个字节?。为什么?

 分析:

struct A自身的对齐长度是1,所以sizeof(struct A)=7这很容易理解.

struct B呢?自身的对齐长度是4,a+b+arr的长度是4+4+5=13,13不能被4整除(或者说13没有按照自身对其长度对齐),所以要在最后补3个字节的洞变成16.

 

补充,如果考虑#pragma pack那么规则如下:

1)数据类型自身的对齐值:就是上面交代的基本数据类型的自身对齐值。

2)指定对齐值:#pragma pack (value)时的指定对齐值value。

3)结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值。

4)数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中较小的那个值。

另外,在GCC中,#pragma pack的默认值是4,vc中默认值是8.这一点差别会带来天差地别的不同,gcc里任何double类型都是按4字节对齐的.

转载于:https://www.cnblogs.com/sirlipeng/p/4792062.html

DSP6713 是德州仪器推出的一款数字信号处理器,其使用的是 TMS320C6713 芯片,对于数据对齐问题,可以通过 C 语言的结构体来解决。 首先,需要定义一个结构体,用于存储需要对齐数据,例如: ```c struct aligned_data { int16_t data1; int16_t data2; } __attribute__((aligned(4))); ``` 在这个结构体,我们定义了两个 16 位的整数类型,同时使用了 GCC 的 `aligned` 属性,指定了结构体的对齐方式为 4 字节对齐。 接下来,我们可以定义一个结构体的指针变量,用于指向需要对齐数据: ```c struct aligned_data *pdata; ``` 然后,我们可以通过 `malloc` 函数为这个指针变量分配内存,同时保证分配的内存地址为 4 的倍数: ```c pdata = (struct aligned_data *)malloc(sizeof(struct aligned_data)) + 3; pdata = (struct aligned_data *)((uint32_t)pdata & ~0x03); ``` 在这个代码,我们先为指针变量分配了内存,然后将指针加上 3,保证其地址为 4 的倍数,最后使用按位取反的方式将地址的最后两位清零。 现在,我们就可以使用 pdata 指针来访问对齐后的数据了,例如: ```c pdata->data1 = 0x1234; pdata->data2 = 0x5678; ``` 这样,就可以保证 DSP6713 数据对齐了。需要注意的是,不同的编译器对于 `aligned` 属性的支持可能有所不同,上面的代码使用的是 GCC 的扩展语法,如果使用其他编译器可能需要使用不同的语法来实现数据对齐
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值