四十四、 联合体/共用体union
- 属于构造类型,不是基本类型
44.1 联合体/共用体union的概念
- 联合体中的成员,公用同一片空间
- 共用体的大小:共用体中占空间最大的成员的字节数,就是共用体的大小
44.2 联合体/共用体union的定义
union 共用体名
{
共用体成员
};
union A
{
int a;
short b;
};
//定义了一个共用体类型
//共用体中有两个成员,int和short
//这两个成员公用同一片内存空间
空间图解:
44.3 使用共用体判断大小端存储问题
直接上代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
union A
{
int a;
char b; //共用体的大小,由共用体中更大的成员决定
};
int main(int argc, const char *argv[])
{
union A u1;
u1.a = 0x12345678;
//大小端存储
if(u1.b==0x78)
{
printf("小端存储\n");
}
else if(u1.b==0x12)
{
printf("大端存储\n");
}
return 0;
}
四十五、 宏define
45.1 使用#将宏替换的结果变化成字符串
- #应用于带参宏中
- #的作用,把带参宏的参数替换成字符串
代码展示:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STR(n) #n
int main(int argc, const char *argv[])
{
printf("%s\n",STR(hello));
return 0;
}
45.2 ## ——> 用于字符串的拼接
- ##可以拼接指定的字符串,但是#只能对带参宏的参数生效
- ##常用于,某些数据类型的宏定义(底层会用到)
代码示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define unit_32 unsigned int
#define TYPE(a,b) a##b
//双##常用于类型的重定义
int main(int argc, const char *argv[])
{
TYPE(unit,_32) a;
a = 90;
printf("%d\n",a);
return 0;
}
45.3 宏函数
- 带参数只能是运算的表达式,宏函数可以有多个表达式,多行使用’'拼接
- 宏函数的返回值,是最后一个表达式的结果,没有return
- 宏函数建议使用{},包起来,
如果不想接收宏函数的结果,{}外面可以不加(),
如果想要使用变量接收宏函数的结果,需要在{}外加()
代码示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//宏函数实现求两个数中的最大值
//宏函数的返回值就是最后一个表达式的结果
#define FUN(a,b) ({int ret; \
if(a>b) \
ret = a;\
else \
ret = b;\
ret = 90;\
ret; \
100;\
10000;})
#define MAX(a,b) ({a>b?a:b;\
1000;900;})
int main(int argc, const char *argv[])
{
int ret = 90;
MAX(10,12);
printf("%d\n",ret);
return 0;
}
45.4 默认系统的辅助编译的宏
打印文件名 : __FILE__
打印行数 : __LINE__
打印函数名 : __func__
45.5 条件编译
- 条件编译,一般发生在预处理阶段
1. #if 表达式(0/1)
代码块1;
#else
代码块2;
#endif
如果表达式为0,代码块1不执行,代码块2执行
表达式为1则相反
2. #ifndef 宏名
代码块;
#endif
如果没有定义过该宏,就执行代码块
3. #ifdef 宏名
代码块;
#endif
如果定义过该宏,就执行代码块
代码示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, const char *argv[])
{
int a;
printf("%d\n",a);
#if 0 //下面这个代码块会被注释掉
double b;
printf("%lf\n",b);
#else
printf("条件不成立\n");
#endif
return 0;
}
四十六、 枚举类型enum
枚举类型是一个基本数据类型
46.1 枚举类型enum的定义
enum 枚举名
{
枚举项,
};
//定义了一个枚举的数据类型
typedef enum 枚举名
{
枚举项,
····
}新的名;
//后面可以直接使用新的名字定义枚举变量
注意事项:
- 枚举变量,建议使用枚举项赋值,为了让枚举变量有意义
- 枚举项是一个常量,枚举项可以直接使用
(即使没有枚举变量也可以使用枚举项) - 枚举项的值默认从0开始,并依次递增,
如果从中间给枚举项赋值,那么后面的枚举项也跟着新的值递增
46.2 枚举类型enum的使用
- (底层枚举会和寄存器一起使用)
以练代学:
假设屋内有三个LED灯,LED1、LED2、LED3
灯有两种状态:开或者是关 LED_ON、LED_OFF,
模拟一个控制灯的初始化,以及控制灯的状态的代码。
#include <stdio.h>
//定义LED灯的枚举类型
enum LED
{
LED1=1,
LED2,
LED3,
};
//定义灯状态的枚举类型
enum CON
{
LED_OFF,
LED_ON,
};
//控制灯的初始化,需要一个LED类型的变量
void led_init(enum LED l1)
{
switch(l1)
{
case LED1:
printf("初始化了LED1\n");
break;
case LED2:
printf("初始化了LED2\n");
break;
case LED3:
printf("初始化了LED3\n");
break;
}
}
//控制灯状态的函数,需要两个参数
//led灯,灯的状态
void con(enum LED l1,enum CON c1)
{
switch(l1)
{
case LED1:
switch(c1)
{
case LED_OFF:
printf("关闭了LED1\n");
break;
case LED_ON:
printf("打开了LED1\n");
break;
}
break;
case LED2:
switch(c1)
{
case LED_OFF:
printf("关闭了LED2\n");
break;
case LED_ON:
printf("打开了LED2\n");
break;
}
break;
case LED3:
switch(c1)
{
case LED_OFF:
printf("关闭了LED3\n");
break;
case LED_ON:
printf("打开了LED3\n");
break;
}
break;
}
}
int main(int argc, const char *argv[])
{
enum LED led = LED3;
//调用初始化函数
led_init(LED1);
led_init(LED2);
led_init(LED3);
//调用控制函数
con(LED1,LED_ON);
con(LED2,LED_ON);
con(LED1,LED_OFF);
return 0;
}