C语言基础_结构体

一、定义结构体

在定义结构体时是不分配内存空间的,只有在定义变量时才会分配内存空间。

若struct后面接的是名字,则其为该结构体的名称。
第一种是最基本的结构体定义,其定义了一个结构体A。

struct A //第一种
{
   int a;
};

第二种则是在定义了一个结构体B的同时定义了一个结构体B的变量m。

struct B //第二种
{
   int b;
}m;

第三种结构体定义没有给出该结构体的名称,但是定义了一个该结构体的变量n,也就是说,若是想要在别处定义该结构体的变量是不行的,只有变量n这种在定义结构体的同时定义变量才行。

struct //第三种
{
    int c;
}n;

第四种结构体定义在第一种结构定义的基础上加了关键字typedef,此时我们将struct D{int d}看成是一个数据类型,但是因为并没有给出别名,直接用D定义变量是不行的。如D test;,不能直接这样定义变量test。但struct D test;可行。

typedef struct D //第四种
{
     int d;
};

第五种结构体定义在第四种结构体定义的基础上加上了别名x,此时像在第四种结构体定义中说得那样,此时的结构体E有别名x,故可以用x定义E的结构体变量。用E不能直接定义,需要在前面加struct,如struct E test;。

typedef struct E //第五种
{
     int e;
}x;

第六种结构体定义在第五种的基础上减去了结构体名,但是若是直接使用y来定义该结构体类型的变量也是可以的。如y test;。(常用)
typedef struct //第六种
{
      int f;
}y;

二、使用示例

typedef struct                            // 功率采样的数据结构体
{
    u16    PmValue;                            // AD值
    u16 SumPmValue;                        // 10个AD值总和
    u16 AveragePmValue;                // 10个AD值的平均值
    u16  PmDetCount;                        // 采样次数
    u8  PmTableLen;                        // 功率表格长度
    s8  PmMax;                                // 最大功率值
    s8  Pm;                                        // 最后得到的功率值(dBm)

} ModulePmTypeDef;

ModulePmTypeDef  Module;//声明变量

Module.PaOutput.Pm//成员变量的直接访问

Module.PaOutput->Pm//成员变量的间接访问

三、结构体内存对齐规则

第一个成员在结构体变量偏移量为0 的地址处。
其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。对齐数=min{编译器默认对齐数,该结构体中最大成员变量的字节数}。vs中默认值是8 Linux默认值为4。
通常来说
32位

指针都是  4个字节

char     1个字节
short 两个字节
int      4个字节
long     4个字节
long int 4个字节
float    4个字节

double    8个字节
long double  8个字节


64位

指针都是一个字长, 8个字节

char    1个字节 
short   2个字节
int     4个字节 

long    8个字节
long int  8个字节
double    8个字节
long double 也可以变长了, 16个字节

结构体总大小为最大对齐数的整数倍。(每个成员变量都有自己的对齐数)
如果嵌套结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(包含嵌套结构体的对齐数)的整数倍。
内存对齐规则应用
接下来我们看一下具体怎么应用这几条规则??

struct S1
{
    char c1;
    char c2;
    int i;
};
printf("%d\n", sizeof(struct S1));


结果是8,我们来分析一下为什么结果是 8??
c1是char型,占一个字节,第一个成员即 c1 在结构体变量偏移量为0 的地址处。
c2是char型,占一个字节,要对齐到对齐数的整数倍的位置。对齐数 = 编译器默认的一个对齐数与该成员大小中的较小值,vs中默认值是8,取较小值1,char类型的对齐数是1,所以对齐到1 的整数倍,那就是偏移量为1开始的地址空间。
i是int类型,占四个字节,要对齐到对齐数的整数倍的位置。int类型的对齐数就是 4,所以对齐到4 的整数倍。
我们来看一下内存分布图:

那我们再来看一下这个输出结果是多少呢

struct S2
{
    char c1;
    int i;
    char c2;
};
printf("%d\n", sizeof(struct S2));


结果是12,来看一下过程?
c1是char型,占一个字节,对应到结构体变量偏移量为0 的地址处。
i是int型,占四个字节,对齐数就是4,对齐到4的整数倍位置处,即偏移量为4开始的地址空间。
c2是char型,占一个字节,对齐到1 的整数倍,那就是下一个地址空间,对齐到偏移量为8的地址空间。
结构体总大小为最大对齐数的整数倍,所以为对齐数4的整数倍,现在已经用了9个字节的空间,那么总大小就是12个字节空间。所以输出结果是12。

看一下内存分布图:

结构体也是可以嵌套使用的,那如果嵌套的话,大小是怎么判断的呢?

struct S3
{
    double d;
    char c;
    int i;
};
struct S4
{
    char c1;
    struct S3 s3;
    double d;
};
printf("%d\n", sizeof(struct S4));



结果是32,我们来看一下分析:
容易得出struct S3占16个字节。
那我们来看一下struct S4的大小,struct S4中有三个成员变量,第一个char型,占一个字节,对齐到偏移量为0的地址处。第二个成员是结构体嵌套使用,结构体S3变量s3,struct S3 对齐的位置应该是S3成员的最大长度,也就是double d的长度为8,所以对齐到偏移量为8的地址空间处。第三个成员是double型,占8个字节,对应到8的整数倍即偏移量24的地址处。
结构体总大小是最大对齐数8的整数倍,所以是32,因为对齐数 = 编译器默认的一个对齐数与该成员大小中的较小值。
来看一下内存分布图:


为什么存在内存对齐呢?
平台原因(移植原因):
不是所有的硬件平台都能访问任意地址的任意数据的;某些平台只能在某些地址处取某些特定类型的数据

性能原因:
数据结构尤其是栈应该尽可能在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要做两次访问内存;而对齐的内存访问仅需要一次访问。
缺点:
这是一种以空间换时间的做法,但这种做法是值得的,有时候为了程序的可读性,也会牺牲掉一些内存空间,不按最小的内存空间的变量定义顺序来进行变量定义。
 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值