1、宏定义
定义一个标记(宏名)用来代表:常量数值、变量、表达式、类型、某一段代
在预处理阶段会把这些标识符的地方使用后面的内容全部替换。
1、代表常量数值
cpp
#define NUM 1000
int arr[NUM]; // int arr[1000];
2、代表变量
cpp
#define M m
int main()
{
int m = 100;
printf("%d",M); // printf("%d",m);
return 0;
}
3、代表表达式
cpp
#define ADD a+b
int main()
{
int a = 10;
int b = 20;
printf("%d",ADD); // printf("%d",a+b); // 30
printf("%d",2*ADD); // printf("%d",2*a+b); // 40
}
// 一般定义宏的时候后面如果是表达式,要用()将这个表达式括起来
cpp
#define ADD (a+b)
int main()
{
int a = 10;
int b = 20;
printf("%d",ADD); // printf("%d",(a+b)); // 30
printf("%d",2*ADD); // printf("%d",2*(a+b)); // 60
}
4、带参数的宏
cpp
#define ADD(a,b) (a+b)
int main()
{
int a = 10;
int b = 20;
int m = 3;
int n = 5;
printf("%d",ADD(a,b)); // printf("%d",(a+b)); // 30
printf("%d",ADD(m,n)); // printf("%d",(m+n));
}
5、给类型起别名
cpp
#define U8 unsigned char
U8 a; // unsigned char a;
typedef unsigned char u8;
在定义指针的时候要小心
#define U8P unsigned char *
U8P a,b; // unsigned char *a,b; // 宏替换, a是指针,b是unsigned char
typedef unsigned char * u8p;
u8p a,b; // a和b都是unsigned char * u8p是数据类型
6、代表某一段代码
cpp
#define code if(1){printf("xxxxxxx");}
int main()
{
code
return 0;
}
练习:
定义一个宏用来求某个数组的数据个数
cpp
#define GETLEN(a) (sizeof(a)/sizeof(a[0]))
int main()
{
int arr[] = {1,7,8,2,45,79,0,1,3,6};
int len = GETLEN(arr); // (sizeof(arr)/sizeof(arr[0]))
printf("%d",len);
}
2、条件编译
根据不同的条件生成不同的目标代码
第一种:
#if ... #endif
#if ... #else ....#endif
cpp
#if 1
printf("bbbbb\n");
#endif
第二种:
#ifdef 宏名 .... #endif
案例:中断使用开关
cpp
#include<stdio.h>
#define STM32f4
typedef enum IRQN
{
IR0,
IR1,
#ifdef STM32f4
IR3,
#endif
IR11
}IR_Type;
int main(void)
{
printf("%d %d %d %d\n",IR0,IR1,IR3,IR11);
return 0;
}
第三种:
#ifndef 宏名
#define 宏名
...
#endif
作用:防止头文件的重复包含 .h文件
创建led.h、led.c模块,在led.h中书写下列代码,防止led.h头文件的重复包含。
cpp
#ifndef _LED_H
#define _LED_H
#include "stm32f10x.h"
#define LEO_ON (GPIOA->ODR &= ~(1 << 4))
void led_init(void);
#endif