成都网站建设设计

将想法与焦点和您一起共享

【C语言】高级宏定义-创新互联

前言

宏定义分为不带参数的宏定义和带参数的宏定义,不带参数的宏定义就是普通的宏定义,带参数的宏定义则稍稍复杂。下面将结合一些例子讲解这些显得比较高级的宏定义。

创新互联-专业网站定制、快速模板网站建设、高性价比宝安网站开发、企业建站全套包干低至880元,成熟完善的模板库,直接使用。一站式宝安网站制作公司更省心,省钱,快速模板网站建设找我们,业务覆盖宝安地区。费用合理售后完善,十载实体公司更值得信赖。文章目录
  • 前言
  • 一、高级宏定义
    • 1、#define M(y) y*y+3*y
    • 2、#define MAX(X,Y) (((x)>(y))?(x):(y))
    • 3、用带参数宏定义多个语句
    • 4、宏定义嵌套
    • 5、#define ABC "abc"
    • 6、用#将宏参数转换为字符串
    • 7、##用于在宏定义中进行连接
    • 8、复杂宏定义1
    • 9、复杂宏定义2
  • 二、答疑
    • 1、宏定义占用内存吗?
    • 2、宏定义作用域
    • 3、define和typedef的区别
    • 4、条件编译中的#define和宏定义中的#define
  • 参考资料


一、高级宏定义 1、#define M(y) yy+3y

这个宏定义中有一个参数,使用时传入参数即可,

k=M(5);  //宏调用

经过替换,变为

k=5*5+3*5
2、#define MAX(X,Y) (((x)>(y))?(x):(y))

机器很笨,为了防止机器理解错误,需要将参数以及整个表达式都加上括号。

调用

MAX(5,3)

会被替换为:

(((5)>(3))?(5):(3))
3、用带参数宏定义多个语句
#define SSSV(s1, s2, s3, v) s1 = length * width; s2 = length * height; s3 = width * height; v = width * length * height;

看完整例子:

#include#define SSSV(s1, s2, s3, v) s1 = length * width; s2 = length * height; s3 = width * height; v = width * length * height;
int main(){int length = 3, width = 4, height = 5, sa, sb, sc, vv;
    SSSV(sa, sb, sc, vv);
    printf("sa=%d, sb=%d, sc=%d, vv=%d\n", sa, sb, sc, vv);
    return 0;
}

sa=12, sb=15, sc=20, vv=60

替换为:

#include#define SSSV(s1, s2, s3, v) s1 = length * width; s2 = length * height; s3 = width * height; v = width * length * height;
int main(){int length = 3, width = 4, height = 5, sa, sb, sc, vv;
    sa = length * width; 
    sb = length * height; 
    sc = width * height; 
    vv = width * length * height;
    printf("sa=%d, sb=%d, sc=%d, vv=%d\n", sa, sb, sc, vv);
    return 0;
}

sa=12, sb=15, sc=20, vv=60
4、宏定义嵌套

下面的宏定义将天,小时,分钟,秒转化为ms

#define SECOND 1000UL//ul为无符号长整形,不加默认为int,可存储数据小
#define MINUTE (SECOND *60)
#define HOUR (MINUTE *60)
#define DAY (HOUR *24)
5、#define ABC “abc”

用宏定义除了定义数字还可以定义字符串

6、用#将宏参数转换为字符串
#include#define STR(s) #s
int main() {printf("%s\n", STR(c.biancheng.net));
    printf("%s\n", STR("c.biancheng.net"));
    return 0;
}

会被替换为

#include#define STR(s) #s
int main() {printf("%s\n", "c.biancheng.net");
    printf("%s\n", "\"c.biancheng.net\"");
    return 0;
}

c.biancheng.net
"c.biancheng.net"

注意转义字符"表示"

7、##用于在宏定义中进行连接
#include#define CON1(a, b) a##e##b
#define CON2(a, b) a##b##00
int main() {printf("%f\n", CON1(8.5, 2));
    printf("%d\n", CON2(12, 34));
    return 0;
}

会被替换为

#include#define CON1(a, b) a##e##b
#define CON2(a, b) a##b##00
int main() {printf("%f\n", 8.5e2);
    printf("%d\n", 123400);
    return 0;
}

850.000000
123400
8、复杂宏定义1
#define osTimerStaticDef(name, function, control)  \
const osTimerDef_t os_timer_def_##name = \
{(function), (control) }

该宏定义是用

osTimerStaticDef(name, function, control)

替换

const osTimerDef_t os_timer_def_##name = \
{(function), (control) }

osTimerDef_t 是一个结构体别名,我们可以看一下它的定义

typedef struct os_timer_def  
{os_ptimer                 ptimer;    ///< start address of a timer function
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
  osStaticTimerDef_t        *controlblock;      ///< control block to hold timer's data for static allocation; NULL for dynamic allocation
#endif
} osTimerDef_t;

用osTimerDef_t定义一个结构体变量,变量名中包含参数name,用##与os_timer_def_连接,达到自动修改结构体变量名的目的。

结构体包含两个成员。

9、复杂宏定义2
#define IS_TICKFREQ(FREQ) (((FREQ) == HAL_TICK_FREQ_10HZ)  ||   ((FREQ) == HAL_TICK_FREQ_100HZ) ||  ((FREQ) == HAL_TICK_FREQ_1KHZ))

先看看HAL_TICK_FREQ_10HZ的定义

typedef enum
{HAL_TICK_FREQ_10HZ         = 100U,
  HAL_TICK_FREQ_100HZ        = 10U,
  HAL_TICK_FREQ_1KHZ         = 1U,
  HAL_TICK_FREQ_DEFAULT      = HAL_TICK_FREQ_1KHZ
} HAL_TickFreqTypeDef;

传入FREQ,只要FREQ100U或FREQ10U或FREQ==1U,就返回true

二、答疑 1、宏定义占用内存吗?

宏定义只是一个预处理命令,在程序编译之前做一个简单的替换,不会占用内存空间,因此宏定义中的参数不用指定数据类型。

2、宏定义作用域

从定义位置开始到当前文件末尾

3、define和typedef的区别

宏定义只是简单的字符串替换,由预处理器来处理;
而 typedef 是在编译阶段由编译器处理的,它并不是简单的字符串替换,而是给原有的数据类型起别名,将它作为一种新的数据类型。

这里给个例子体验一下:

typedef struct node
{int a;
	char b;
}Node;

这里就是用typedef给结构体node取一个别名Node,以后用它定义结构体变量,就可以直接用Node

Node node1;

而不需要使用下面这种方式定义:

struct node node2;

完整代码如下:

#includetypedef struct node
{int a;
	char b;
}Node;

int main()
{Node node1;	
	node1.a=10;
	node1.b='a' ;
	printf("node1.a=%d,node1.b=%c\r\n",node1.a,node1.b);
	struct node node2;
	node2.a=20;
	node2.b='b' ;
	printf("node2.a=%d,node2.b=%c\r\n",node2.a,node2.b);
	return 0;
}

node1.a=10,node1.b=a
node2.a=20,node2.b=b

可以看到,typedef就是给这个结构体取一个别名,不是简单替换。

再看一个例子:

#define PIN1 int*
typedef int* PIN2;//注意;不要忘记

下面用PIN1定义两个变量

PIN1 a,b;

经过预处理器替换后,代码变为:

int* a,b;

其中a是一个指向整型的指针变量,b是一个整型变量。

同样,用PIN2定义两个变量

PIN2 a,b;

a,b均为指向整型的指针变量。


4、条件编译中的#define和宏定义中的#define

预处理命令包括:宏定义、文件包含、条件编译

(1) 一般宏定义的格式为 #define 宏名 被替换字符串;

(2) C语言的文件包含,就是以 #Include开头之后,引用的文件;

(3) 条件编译可以作为头文件卫士

#ifndef FILE_H // 判断FILE_H宏是否正在,不存在则条件为真

#define FILE_H // 定义FILE_H宏,注意与普通宏定义的区别!!!

#endif // FILE_H   // #ifndef的结尾

这种固定写法,一般在头文件中使用,它能防止头文件被重复包含。
参考资料

1、http://c.biancheng.net/view/1982.html
2、https://blog.csdn.net/m0_37689444/article/details/88852630

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


名称栏目:【C语言】高级宏定义-创新互联
网站路径:http://chengdu.cdxwcx.cn/article/pscjp.html