目录
十二、共用体、枚举、宏定义、条件编译
12.1共用体
12.2枚举
12.3宏定义
12.4条件编译
十二、共用体、枚举、宏定义、条件编译
12.1共用体
1多个成员共用同一块内存,
2所有成员的首地址都是一样的。
3共用体类型占据空间大小是里面占用空间最多成员所占字节数,同时也要满足是 分配单位 整数倍。
定义共用类型:
union 共用体名
{成员类型 成员名;成员类型 成员名;.....
};共用体类型:union 共用体名union data
{char ch;int a;
};// 共用体类型名称:union dataprintf ("%d", sizeof (union data)); // 4union data1
{char name[21];int b;
};printf ("%d", sizeof (union data)); // 24
共用体变量:
union data d1;//点语法
//d1.ch &d1.ch
//d1.a &d1.a#include<stdio.h>union data
{char ch;int a;
};int main (void)
{// 数据类型大小 printf ("%d\n", sizeof (union data));// 如何看成员在内存分布union data d1;printf ("%p %p\n", &(d1.ch), &(d1.a));d1.a = 0x12345678;printf ("%x\n", d1.ch); // 0x78d1.ch = 0xaa;printf ("%x\n", d1.a); // 0x123456aa;return 0;
}
应用场景:
1、可以将多字节的数据一个一个取出来
#include<stdio.h>union data
{unsigned int a;unsigned char arr[4];
};int main (void)
{union data d1;d1.a = 0x12345678;printf ("%x %x %x %x\n", d1.arr[3], d1.arr[2], d1.arr[1], d1.arr[0]);return 0;
}2、结合位域 -- 结构体可以将一个数据的每一位取出来
位域 -- 结构体strcut 结构体名
{成员类型 成员名 : 2; // 2--2位 是位域的意思成员类型 成员名 : 2;...
};需求:8位的数据需要取出来数据的每一位,而且不开额外的空间。union SplitByte
{unsigned char a;struct BIT{unsigned char a0 : 1;unsigned char a1 : 1;unsigned char a2 : 1;unsigned char a3 : 1;unsigned char a4 : 1;unsigned char a5 : 1;unsigned char a6 : 1;unsigned char a7 : 1;}bits;
};int main ()
{union SplitByte b1;b1.a = 0xae; // 10101110printf ("%d %d %d %d %d %d %d %d\n", b1.bits.a7, b1.bits.a6, b1.bits.a5, b1.bits.a4, b1.bits.a3, b1.bits.a2, b1.bits.a1, b1.bits.a0);return 0;
}
12.2枚举
罗列一些大写标识符,当做整型数据来使用, 代码易读。
枚举标识符如果没有赋值,默认从0开始,后面项依次增加1.
枚举标识符有赋值就用赋的数值,后面项没有赋值的依然是在前一项依次增加1.
enum 枚举名称
{标识符1, 标识符2, ......
}; // 枚举类型:enum 枚举名称举例:
罗列星期英文 当做星期数字使用。enum week
{MON, TUES, WEDS, THIR, FRI, SAT, SUN
}; // 0 1 2 3 4 5 6 代码:
#include<stdio.h>enum week
{MON = 1, TUES = 15, WEDS = 10, THIR = 19, FRI, SAT, SUN
}; // 1 15 10 19 20 21 22int main (void)
{printf ("%d %d %d %d %d %d %d\n", MON, TUES, WEDS, THIR, FRI, SAT, SUN);enum week a; // 定义变量 printf ("%d", sizeof (enum week)); // 4return 0;
}
12.3宏定义
定义一个标识符名 可以代表常量 、变量 、表达式 、 数据类型 .
在 预处理阶段 进行宏替换。
1、标准宏
2、带参宏
格式:
#define 宏名 代表内容例子:
#define PI 3.1415926
#define BOOKNUM 100// 求一个半径为3的圆的面积
// π*r*rfloat area = PI * 3 * 3; // 3.1415926 * 3 *3
printf ("%f", area);// 开BOOKNUM个结构体数组
BK arr[BOOKNUM];例子:
写一个宏,代表 a + b的和#include<stdio.h>#define ADD a+b
#define ADD1 (a+b)int main ()
{int a = 20;int b = 30;int res = ADD; // int res = a + b;printf ("%d\n", res);int res1 = 2 * ADD; // int res1 = 2 * a + b; = 2*20+30 = 70printf ("%d\n", res1);int res2 = 2 * ADD1; // int res2 = 2*(a+b); = 2*(20+30) = 100printf ("%d\n", res2);return 0;
}注意:
一般用宏名代表某一个表达式的时候,我们会用 ()将表达式包裹起来。
#define ADD1 (a+b)
12.4条件编译
根据不同的条件生成不同的目标代码
#if 常量
代码块
#endif
#if 1#include<stdio.h>#define LED1_ON printf("on")
#define LED1_OFF printf("off")int main (void)
{int res;scanf ("%d", &res);if (res == 1){LED1_ON;}else{LED1_OFF;}return 0;
}#endif
#if 常量
代码块1
#else
代码块2
#endif
#include<stdio.h>int main (void)
{printf ("串口1的配置\n");#if 0printf ("发送代码\n");
#elseprintf ("接受端的代码");
#endif printf ("串口1的关闭\n");return 0;
}// 常量为真 -- 目标代码
// printf("串口1的配置\n");
// printf("发送代码\n");
// printf("串口1的关闭\n");// 常量为假 -- 目标代码
// printf("串口1的配置\n");
// printf("接受端的代码\n");
// printf("串口1的关闭\n");通过条件编译可以节省代码区的代码,一份代码可以维护两个端。
#ifdef 宏名
代码块
#endif如果定义了宏名 ,就将代码块打包到目标代码里面去。
如果没有定义了宏名 ,就不打包。#include<stdio.h>#define RECVint main (void)
{printf ("串口1的配置\n");#ifdef RECVprintf ("接收端代码\n");
#endif printf ("串口1的关闭\n");return 0;
}
#ifndef 宏名
#define 宏名
代码块
#endif#ifndef _LED_H
#define _LED_H// 宏定义 类型定义
#define LED1_ON printf("yes") typedef struct student
{int bno;char name[20];
}STU;// 函数声明
void led_init (void);#endif