从单片机基础到程序框架(全集 2019pdf版).pdf - 第309页

a=sizeof(G tMould_1) ; //利用宏函数 si zeof 获取结构体 变量所占用的 字节总 数 } 【71.4 结构体之间的赋值。 】 结构体之间 的赋值有两种 ,第一种是成 员之间 “一对一” 的赋值,第 二种是整个结 构体之间 “面对面” 的整体赋值。 第一 种成员赋值像 普通变量赋 值那样, 没有 那么多套路和 忌讳, 数据传递安 全可靠。 第二种整 个结 构体之 间赋 值在编 程体 验上 带有“一 键操作 ”…

100%1 / 836
{
unsigned long u32Data; //一个 unsigned long 4 个字节。
unsigned char u8Data; //一个 unsigned char 占用 1 个字节
};
struct StructMould_1 GtMould_1; //占用多少个字节内存呢?
分析:更 u8Data u32Data 位置顺序,u32Data u8Data 在后,GtMould_1 这个变量用多
少个内存字节呢?假设 GtMould_1 的首地址是 0,那么地址 0 就存放成员 u32Data,u32Data 占用 4 个字节,
所以接下来的地址是 4(0+4)那么问题来了,地址 4 能直接存放占用 1 个字节的成 u8Data 吗?能。
32 位单片机的“对齐倍数”是 4(32 除以 8)那么地址 4 显然是可以整除“对齐倍数”4 的,因此,地址 4
是可以果断存储 u8Data 的。那么,是不 GtMould_1 占用 5 个字节呢?不是。因为结构体的内存对齐,
还包括另外一条规定,那就是“一个结构体变量所占的内存总容量必须能整除该单片机的“对齐倍数
片机的位数除以 8)如果不能,C 编译器就会擅自在最后一个成员的后面插入若干个“填充字节”来满足这
个规则”根据这条规定,计算所得的总容量 5 是不能整除“对齐倍数”4 必须再额外填充 3 个字节补足
8,才能整除“对齐倍数”4,因此,更改顺序后,GtMould_1 还是占用 8 个字节(4+1+3),前 4 个字节是
u32Data,中间 1 个字节是 u8Data,后 3 个字节是“填充字节”
因为本教程采用的是 8 位的 51 内核单片机因此在上述这个例子中,GtMould_1 所占的字节数是符合
“第一个例子的情况,也就是占用 5 字节。内存对齐是遵守几条严格的规则的我只列出其中最关键的
两条给大家大致阅读一下,有一个印象即可,不强求死记硬背,只需知道“结构体因为存在内存对齐所以
实际内存容量是有可能大于内部各成员类型字节数相加之和,尤其 16 位或者 32 位这类单片机”就可以了。
(1)结构体内部某个成员相对结构体首地址的偏移地址必须能整除该单片机的“对齐倍数”(单
片机的位数除以 8),如果不能,C 编译器就会擅自在各成员之间插入若干个“填充字节”来满足这个规则。
(2)一个结构体变量所占的内存总容量必须能整除该单片机的“对齐倍数”单片机的位数除以
8),如果不能,C 编译器就会擅自在最后一个成员的后面插入若干个“填充字节”来满足这个规则。
【71.3 如何获取某个结构体变量的内存容量?】
结构体存在内存对齐的问题,就说明它的内存占用情况不会像普通数组那样一目了然那么,我们编写
程序的时候怎么知道某个结构体变量占用了多少个字节数?答案是:用 sizeof 宏函数。比如:
struct StructMould_1
{
unsigned long u32Data;
unsigned char u8Data;
};
struct StructMould_1 GtMould_1;
unsigned long a; //此变量用来获取结构体变 GtMould_1 所占用的字节总数
void main() //主函
{
a=sizeof(GtMould_1); //利用宏函数 sizeof 获取结构体变量所占用的字节总
}
【71.4 结构体之间的赋值。
结构体之间的赋值有两种,第一种是成员之间“一对一”的赋值,第二种是整个结构体之间“面对面”
的整体赋值。第一种成员赋值像普通变量赋值那样,没有那么多套路和忌讳,数据传递安全可靠。第二种整
个结构体之间赋值在编程体验上带有“一键操作”的快感,但是要注意避开一些“雷区”,首先,整体赋值
的前提是必须保证两个结构体变量都是同一个“结构体模板”造出来的变量,不同“模板”的结构体变量之
间禁止“整体赋值,其次,哪怕是“同一个模板”的结构体变量,也并不是所有的“同模板结构体”变
都能实现整个结构体之间的直接赋值,只有在结构体内部成员比较简单的情况下才适合“整体赋值,如果
结构体内部包含有“指针”或者“字符串”或者“其它结构体中的结构体这类情况就比较复杂,这时
议大家绕开有“雷区“整体赋值”而直接选用安全可靠的“成员赋值”什么是成员赋值”什么是
体赋值”?请看下面两个例子。
第一种:成员赋值。把结构体变量 GtMould_2_A 赋值 GtMould_2_B。
struct StructMould_2 //“造模”
{
unsigned long u32Data;
unsigned char u8Data;
};
struct StructMould_2 GtMould_2_A; //生成第 1 个结构体变量
struct StructMould_2 GtMould_2_B //生成第 2 个结构体变
void main() //主函
{
//先给 GtMould_2_A 赋初值
GtMould_2_A.u32Data=1;
GtMould_2_A.u8Data=2;
//通过“成员赋值”,把结构体变量 GtMould_2_A 赋值 GtMould_2_B。
GtMould_2_B.u32Data=GtMould_2_A.u32Data; //成员之间“一对一”的赋
GtMould_2_B.u8Data=GtMould_2_A.u8Data; //成员之间“一对一”的赋值
}
第二种:整体赋值。把结构体变量 GtMould_2_A 赋值 GtMould_2_B。
struct StructMould_2 //“造模”
{
unsigned long u32Data;
unsigned char u8Data;
};
struct StructMould_2 GtMould_2_A; //生成第 1 个结构体变量
struct StructMould_2 GtMould_2_B //生成第 2 个结构体变
void main() //主函
{
//先给 GtMould_2_A 赋初值
GtMould_2_A.u32Data=1;
GtMould_2_A.u8Data=2;
//通过“整体赋值”,把结构体变量 GtMould_2_A 赋值 GtMould_2_B。
GtMould_2_B=GtMould_2_A; //整体之间“一次性”的赋
}
上述例子中的整体赋值,是因为结构体内部的数据比较“简单”没有包含“指针”或者“字符串”或
“其它结构体中的结构体这类数据成员,如果包含这类成员,建议大家不要用整体赋值比如遇到以
这类结构体就建议大家直接用安全可靠的“成员赋值”
struct StructMould //“造模
{
unsigned char u8String[]=”String”; //字符
unsigned char *pu8Data; //指针
struct StructOtherMould GtOtherMould; //结构体中的结构体
};
【71.5 例程练习和分析。
现在编写一个练习的程序
/*---C 语言学习区域的开始。-----------------------------------------------*/
struct StructMould_1 //“造模”
{
unsigned long u32Data; //一个 unsigned long 4 个字节。
unsigned char u8Data; //一个 unsigned char 占用 1 个字节
};
struct StructMould_2 //“造模”
{
unsigned char u8Data;
unsigned long u32Data;
};
struct StructMould_1 GtMould_1; //占用多少个字节内存呢?