嵌入式学习日志_Day19:结构体、共用体、枚举、位运算
目录
第八章 构造数据类型
一、结构体(重点)
1 格式:定义一个类型(只是一个架子,知道里面包含什么就行)
2 定义结构体变量
3 结构体变量的定义与初始化
4 访问
通过 变量名. 来选择访问的对象 使用 . 运算符 eg: s.
通过指针 -> 来访问 eg: p->
5 关联(嵌套)另一个结构体
当关联另一个结构体时局部初始化
当关联另一个结构体时访问
6 结构体的存储(以简单结构体为例)
占用空间大小:
具体计算方法:
7 结构体传参--作为函数参数:传的都是结构体的地址
8 结构体数组--但不能叫二维数组
二、共用体--相对结构体来说用的少
定义的语法
cpu的字节顺序(大小端与多字节 2、4、8byte有关)
三、枚举类型--取值范围已确定
1 定义语法
第九章 位运算
第八章 构造数据类型
一、结构体(重点)
1 格式:定义一个类型(只是一个架子,知道里面包含什么就行)
struct 类型名
{
数据类型 成员变量名1;
数据类型 成员变量名2;
数据类型 成员变量名3;
};
类型名:等同于int,char,double,与它们同等级别
2 定义结构体变量
int a;
strcut 结构体名 变量名;
//示例
strcut stu zhangsan;
3 结构体变量的定义与初始化
//全部初始化:结构体变量定义+初始化 全填
strcut stu s={"zhangsan",20,'m',90};
//gnu(gcc) 局部初始化 填部分
strcut stu s1={.name="lisi",.score=90};
//信息我还不知道,先开个空之后再装 先不填
strcut stu s2={0};
4 访问
通过 变量名. 来选择访问的对象 使用 . 运算符 eg: s.
//修改内容
s.age = 22; //int
strcpy(s.name ,"zhang123"); // char []
printf("name:%s age:%d sex:%c score:%d",s.name,s.age,s.sex,s.score);
通过指针 -> 来访问 eg: p->
struct stu *p=&s; //struct stu
printf("name:%s age:%d sex:%c score:%d",p->name,p->age,p->sex,p->score);
5 关联(嵌套)另一个结构体
struct Data
{
int year;
int mon;
int day;
}
struct Stu
{
char name[50];
int age;
char sex;
int score;
}g_s2; //相当于定义了一个全局变量
struct Stu g_s1;
int main()
{
// 全部初始化
struct Stu s ={"zhangsan",20,'m',90, {2000,1,1}}; // struct stu
当关联另一个结构体时局部初始化
// gnu(gcc) 局部初始化
struct Stu s2 = {
.name="zhagnsan",
.score = 80,
.date={
.year =1999,
}
};
当关联另一个结构体时访问
//使用 变量名. 来访问
printf("name:%s age:%d sex:%c score:%d year:%d
",s.name,s.age,s.sex,s.score,s.date.year);
//使用指针 -> 来访问
struct Stu * p = &s; // struct stu
printf("name:%s age:%d sex:%c score:%d month:%d
",p->name,p->age,p->sex,p->score,p->date.month);
6 结构体的存储(以简单结构体为例)
占用空间大小:
字节对齐问题
由于结构体是自定义类型,成员变量根据需要来定义的,cpu(32bit)在访问数据时,都是以4字节为单位读写,效率高,自己定义成员变量的相对地址不一定在4字节对齐的地址,那么编译器就会帮你把成员变量的地址扩展到4字节对齐的地方,那么结构体的大小就会比预测的要变大
具体计算方法:
- 结构体成员必须存放在内存地址为自身类型大小的整数倍的内存地址(起始地址与内存大小取余要求等于0,不足补0直到满足取余等于0)
- 找到结构体中成员变量占用内存最大的(基类型),那么结构体的总大小应该是最大成员占用内存大小的整数倍
图例与示例代码

#include
//这只是个内存模型,告诉计算机装东西的顺序
struct Stu
{
char name[30]; //不要再结构体定义的位置初始化
int age;
short ID;
double cost;
};
int main()
{
int a;
struct Stu s1;
//默认4字节对齐
printf("size is %lu
",sizeof(struct Stu));
return 0;
}
7 结构体传参--作为函数参数:传的都是结构体的地址
示例代码:
#include
#include
struct Stu
{
char name[30];
int age;
char sex;
double score;
};
void input_stu(struct Stu *p)
{
printf("input name:
");
gets(p->name); // zhangsan
printf("input age:
");
scanf("%d",&(p->age));// 20
输入缓冲区//通过p访问到age的地址
getchar(); //从终端上接收一个字符,刚好把
就拿走啦
printf("input sex:
");
// 如果没有getchar(),那么输入缓冲区中还剩一个
,会让用户跳过sex的输入
scanf("%c",&(p->sex));
printf("input score:
");
scanf("%lf",&(p->score));
}
//常量指针,不会对内容进行修改,所以可以加上const
void show_stu(const struct Stu *p)
{
//找个低优先级的折过去,便于观看
printf("name:%s age:%d sex:%c score:%lf",
p->name,p->age,p->sex,p->score);
}
int main()
{
struct Stu s;
input_stu(&s);
show_stu(&s);
return 0;
}
8 结构体数组--但不能叫二维数组
示例代码:
#include
#include
struct Stu
{
char name[30];
double heigh;
};
//定义结构体数组
int main()
{
struct Stu a[3]={0};
struct Stu a2[3]={
{"zhangsan",1.77},
{"lisi",1.65},
{"wangmazi",1.22}
};
//gnu 初始化一部分
struct Stu a3[3]={
[1]={.name="zhangfei",
}
};
//a[0]包含了name与heigh
strcpy(a[0].name,"aaa");
a[0].heigh = 1.11;
//a=a2 错误,数组与数组不能赋值
a[1]=a[0];// 结构体变量与结构体变量之间可以直接赋值
int i=0;
for(i=0;i<3;i++)
{
printf("id:%d name:%s heigh:%lf
",i,a2[i].name,a2[i].heigh);
}
return 0;
}
二、共用体--相对结构体来说用的少
共用体是为了在早期计算机中节省内存的一种自定义结构,也叫联合体,其中成员变量的内存空间是共享的,应用场景:函数参数传递
结构体中,每个成员变量的内存空间是独立的
定义的语法
union 共用体名字
{
数据类型 成员变量名1;
数据类型 成员变量名2;
数据类型 成员变量名3;
......
}
示例代码:由于成员变得的空间是共享的且等于最大的基类型内存空间,之前char写的内容会被int盖住,“谁最后装,谁的东西就在”
#include
//定义一个联合体
union Stu
{
char c;
short s;
int i;
double d;
};
int main()
{
union Stu s;
s.c='a';
s.i=2048;
printf("sizeof is %lu
",sizeof(union Stu));
printf("char:%c int:%d
",s.c,s.i);
return 0;
}
cpu的字节顺序(大小端与多字节 2、4、8byte有关)
大端存储:51单片机,网络,数据的高位在内存的低地址,数据的低位在内存的高地址
小端存储:arm,intel,数据的低位在内存的低地址,数据的高位在内存的高地址
验证大小端示例代码:两种代码任选一种即可--现在可运行的代码是用指针来检验的
#include/* union End { int i; char c; }; int main() { union End e; e.i = 0x12345678; printf("%x ",e.c); return 0; }*/ int main() { int i = 0x12345678; char * p = (char*)&i; printf("%x ",*p); }
三、枚举类型--取值范围已确定
把变量的取值范围一个个列举出来,那么变量只能在这个范围内取值,被列举出来的值叫做枚举值,类型当作整形常量看待
1 定义语法
enum 枚举类型名 {枚举值列表};
//枚举值默认从零开始
enum WEEK { mon,tue,wen,thu,fri,sat,sun};
//枚举值默认从2开始,后一个枚举值在前一个枚举值的基础上+1
enum WEEK { mon=2,tue,wen,thu,fri,sat,sun};
示例代码:有初始化
#include
//定义一个枚举类型,内容当整形常量看
enum WEEK { mon,tue,wen,thu,fri,sat,sun};
//枚举值默认从零开始
int main()
{
enum WEEK w = tue;//变量定义+初始化
w = sun; // w的类型是int
switch(w)
{
case mon:
case tue:
case wen:
printf("goodgoodstudy
");
break;
case thu:
case fri:
case sat:
printf("play
");
break;
case sun:
printf("play!!!
");
break;
}
// w=100; 注意枚举值赋值的时候不要超出范围,gcc不会报警,但逻辑上有问题
return 0;
}
第九章 位运算
先把数据转换成2进制,再对2进制位进行相关操作(与或非)
位运算--可以操作整形类的数据(char,int,short,long)

示例代码:
#include
int main()
{
short a =2220 ;
// 判断某个2进制位 是否为0
//int ret = a & 32;
int ret = a & (1<<5);
if(ret)
{
printf("对应位为真
");
}
else
{
printf("对应位为假
");
}
// | 把某个2进制位 置1
// 将变量 a 的二进制第 6 位强制置为 1,其余位保持原有值不变
ret = a| (1<<6);
printf("| a %d
",ret);
int i = 5;
int j = 6;
i=i^j;
j=j^i;
i=i^j;
printf("i :%d j:%d
",i,j);
return 0;
}










