电子发烧友网 > 嵌入式技术 > 正文

c语言宏定义的使用方法

2020年07月02日 15:04 次阅读

1 概述
        在工程规模较小,不是很复杂,与硬件结合紧密,要求移植性的时候,可采用宏定义简化编程,增强程序可读性。

当宏作为常量使用时,C程序员习惯在名字中只使用大写字母。但是并没有如何将用于其他目的的宏大写的统一做法。由于宏(特别是带参数的宏)可能是程序中错误的来源,所以一些程序员更喜欢使用大写字母来引起注意。

简单宏定义

无参宏的宏名后不带参数,其定义的一般形式为:

#define 标识符 字符

// 不带参数的宏定义#define MAX 10

注意:不要在宏定义中放置任何额外的符号,比如“=”或者尾部加“;”

使用#define来为常量命名一些优点:

程序会更易读。一个认真选择的名字可以帮助读者理解常量的意义;

程序会更易于修改。我们仅需要改变一个宏定义,就可以改变整个程序中出现的所有该常量的值;

可以帮助避免前后不一致或键盘输入错误;

控制条件编译;

可以对C语法做小的修改;

带参数的宏

带参数的仍要遵循上述规则,区别只是宏名后面紧跟的圆括号中放置了参数,就像真正的函数那样。

#define 《宏名》(《参数列表》) 《宏体》

注意参数列表中的参数必须是有效的c标识符,同时以,分隔

算符优先级问题:

#define COUNT(M) M*Mint x=5;print(COUNT(x+1));print(COUNT(++X));//结果输出:11 和42 而不是函数的输出36

注意:

预编译器只是进行简单的文本替换,COUNT(x+1)被替换成COUNT(x+1 x+1),5+15+1=11,而不是36

CUNT(++x)被替换成++x*++x即为6 *7=42,而不是想要的6*6=36,连续前置自加加两次

解决办法:

用括号将整个替换文本及每个参数用括号括起来print(COUNT((x+1));

即便是加上括号也不能解决第二种情况,所以解决办法是尽量不使用++,-等符号;分号吞噬问题:

#define foo(x) bar(x); baz(x)

假设这样调用:

if (!feral) foo(wolf);

将被宏扩展为:

if (!feral) bar(wolf);baz(wolf);

==baz(wolf);==,不在判断条件中,显而易见,这是错误。如果用大括号将其包起来依然会有问题,例如

#define foo(x) { bar(x); baz(x); }if (!feral) foo(wolf);else bin(wolf);

判断语言被扩展成:

if (!feral) { bar(wolf); baz(wolf);}》》++;++《《else bin(wolf);

==else==将不会被执行

解决方法:通过==do{…}while(0)

#define foo(x) do{ bar(x); baz(x); }while(0)if (!feral) foo(wolf);else bin(wolf);

被扩展成:

#define foo(x) do{ bar(x); baz(x); }while(0)if (!feral) do{ bar(x); baz(x); }while(0);else bin(wolf);

注意:使用do{…}while(0)构造后的宏定义不会受到大括号、分号等的影响,总是会按你期望的方式调用运行。

#运算符

#的作用就是将#后边的宏参数进行字符串的操作,也就是将#后边的参数两边加上一对双引号使其成为字符串。例如a是一个宏的形参,则替换文本中的#a被系统转化为“a”,这个转换过程即为字符串化。

#define TEST(param) #paramchar *pStr=TEST(123);printf(“pSrt=%s\n”,pStr);//输出结果为字符 ”123“

##运算符

##运算符也可以用在替换文本中,它的作用起到粘合的作用,即将两个宏参数连接为一个数

#define TEST(param1,param2) (param1##param2)int num =TEST(13,59);printf(“num=%d\n”,num);//输出结果为:num=1359

VA_ARGS

作用主要是为了方便管理软件中的打印信息。在写代码或DEBUG时通常需要将一些重要参数打印出来,但在软件发行的时候不希望有这些打印,这时就用到可变参数宏了。

# define PR(。..) printf(_VA_ARGS_)2 PR(“hello world\n”);34 输出结果:hello world

2 一些建议虽然宏定义很灵活,并且通过彼此结合可以产生许多变形用法,但是C++/C程序员不要定义很复杂的宏,宏定义应该简单而清晰。

宏名采用大写字符组成的单词或其缩写序列,并在各单词之间使用“_”分隔。

如果需要公布某个宏,那么该宏定义应当放置在头文件中,否则放置在实现文件(.cpp)的顶部。

不要使用宏来定义新类型名,应该使用typedef,否则容易造成错误。

给宏添加注释时请使用块注释(/* */),而不要使用行注释。因为有些编译器可能会把宏后面的行注释理解为宏体的一部分。

尽量使用const取代宏来定义符号常量。

对于较长的使用频率较高的重复代码片段,建议使用函数或模板而不要使用带参数的宏定义;而对于较短的重复代码片段,可以使用带参数的宏定义,这不仅是出于类型安全的考虑,而且也是优化与折衷的体现。

尽量避免在局部范围内(如函数内、类型定义内等)定义宏,除非它只在该局部范围内使用,否则会损害程序的清晰性。

3 宏的常见用法防止一个头文件被重复包含

#ifndef COMDEF_H#define COMDEF_H//头文件内容#endif

得到指定地址上的一个字节或字

#define MEM_B(x) (*((byte *)(x)))#define MEM_W(x) (*((word *)(x)))

求最大值和最小值

#define MAX(x,y) (((x)》(y)) ? (x) : (y))#define MIN(x,y) (((x) 《 (y)) ? (x) : (y))

得到一个field在结构体(struct)中的偏移量

#define FPOS(type,field) ((dword)&((type *)0)-》field)

得到一个结构体中field所占用的字节数

#define FSIZ(type,field) sizeof(((type *)0)-》field)

按照LSB格式把两个字节转化为一个Word

#define FLIPW(ray) ((((word)(ray)[0]) * 256) + (ray)[1])

得到一个字的高位和低位字节

#define WORD_LO(xxx) ((byte) ((word)(xxx) & 255))#define WORD_HI(xxx) ((byte) ((word)(xxx) 》》 8))

将一个字母转换为大写

#define UPCASE(c) (((c)》=‘a’ && (c) 《= ‘z’) ? ((c) – 0×20) : (c))

判断字符是不是10进制的数字

#define DECCHK(c) ((c)》=‘0’ && (c)《=‘9’)

判断字符是不是16进制的数字

#define HEXCHK(c) (((c) 》= ‘0’ && (c)《=‘9’) ((c)》=‘A’ && (c)《= ‘F’) \((c)》=‘a’ && (c)《=‘f’))

防止溢出的一个方法

#define INC_SAT(val) (val=((val)+1》(val)) ? (val)+1 : (val))

返回数组元素的个数

#define ARR_SIZE(a) (sizeof((a))/sizeof((a[0])))

下载发烧友APP

打造属于您的人脉电子圈

关注电子发烧友微信

有趣有料的资讯及技术干货

关注发烧友课堂

锁定最新课程活动及技术直播

电子发烧友观察

一线报道 · 深度观察 · 最新资讯
收藏 人收藏
分享:

评论

相关推荐

嵌入式C语言进阶课程

实际工程经验为蓝本,结合C语言中易错和长期被误解的知识点进行深度讲解。
发烧友学院发表于 2018-12-14 00:00 5263次阅读
嵌入式C语言进阶课程

C语言二级指针的用法与原理

提到指针,我们都知道指针是用来存储一个变量的地址。所以,当我们定义了一个指向指针的指针的时候(poi....
发表于 2020-07-02 14:52 3次阅读
C语言二级指针的用法与原理

HW资料华-为硬件(硬件开发C语言PCB设计天线通信)

链接:https://pan.baidu.com/s/1HFxkb4O1jAZvCEccWVcd4w 提取码:stns 回复可见提取码,资源需求可加q1...
发表于 2020-07-01 18:20 50次阅读
HW资料华-为硬件(硬件开发C语言PCB设计天线通信)

C语言和PHP,新手选择哪个比较好?

计科专业从事嵌入式开发多年,从现在的市场行情以及就业的机会上讲php的就业空间还是大于C语言,但并不....
发表于 2020-07-01 16:15 47次阅读
C语言和PHP,新手选择哪个比较好?

Python的发展趋势,未来可期

首先,当前Python作为一门流行程度比较高的全场景编程语言,在IT互联网行业和一部分传统行业已经有....
发表于 2020-07-01 10:19 116次阅读
Python的发展趋势,未来可期

详谈选择排序算法的定义和过程

选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是:第一次从待排序的数....
发表于 2020-06-30 17:06 47次阅读
详谈选择排序算法的定义和过程

C语言模拟实现memmove函数

memmove用于从src拷贝count个字节到dest,如果目标区域和源区域有重叠的话,memmo....
发表于 2020-06-29 17:53 63次阅读
C语言模拟实现memmove函数

C语言模拟实现memcpy函数

memcpy指的是c和c++使用的内存拷贝函数,memcpy函数的功能是从源src所指的内存地址的起....
发表于 2020-06-29 17:29 137次阅读
C语言模拟实现memcpy函数

C语言模拟实现strcmp函数

C语言模拟实现strcmp函数
发表于 2020-06-29 16:51 148次阅读
C语言模拟实现strcmp函数

C语言模拟实现strstr函数

strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串。如果是,则该函数....
发表于 2020-06-29 16:36 293次阅读
C语言模拟实现strstr函数

C语言模拟实现strcat函数

C语言模拟实现strcat函数
发表于 2020-06-29 16:18 101次阅读
C语言模拟实现strcat函数

C语言模拟实现strcpy

strcpy是一种C语言的标准库函数,strcpy把从src地址开始且含有’\0’结束符的字符串复制....
发表于 2020-06-29 15:54 98次阅读
C语言模拟实现strcpy

C语言模拟实现strlen的步骤

strlen所作的仅仅是一个计数器的工作,它从内存的某个位置(可以是字符串开头,中间某个位置,甚至是....
发表于 2020-06-29 15:48 119次阅读
C语言模拟实现strlen的步骤

图文详解:数组和指针的传参

数组传参时,会退化为指针,所以我们先来看看什么是退化!
发表于 2020-06-29 15:34 85次阅读
图文详解:数组和指针的传参

详谈C语言和C++的区别和联系

在学习了C语言和C++之后,这两者之间的区别我们需要仔细的捋一捋!
发表于 2020-06-29 14:56 48次阅读
详谈C语言和C++的区别和联系

单片机程序开发的语言怎么选择

单片机程序的开发可以使用的两种语言,分别是C语言和汇编语言。这里要指出的一件事是,这不是嵌入式单片机....
发表于 2020-06-29 11:22 259次阅读
单片机程序开发的语言怎么选择

C语言精华知识:表驱动法编程实践

根据字典中的部首检字表查找读音未知的汉字就是典型的表驱动法,即以每个字的字形为依据,计算出一个索引值....
发表于 2020-06-28 17:10 124次阅读
C语言精华知识:表驱动法编程实践

聊聊我为什么热爱开源

后面的学习过程中,接触了单片机,我发现这东西也很有趣,能做点小东西,做个时钟、小车、LED小蛮腰。。....
发表于 2020-06-28 17:07 105次阅读
聊聊我为什么热爱开源

Linux TraceEvent - 史上最长宏...

看完了例子,我们就该看代码实现了。讲真,这是我见过的最长的宏展开了。之前在qemu上看到的那个hmp....
发表于 2020-06-28 09:34 155次阅读
Linux TraceEvent - 史上最长宏...

初次接触单片机,你会选择哪款?

其实,模拟电子、数字电子、c语言、汇编这些课程,就是为学单片机课程打下基础。单片机课程涉及到众多专业....
发表于 2020-06-25 17:33 59次阅读
初次接触单片机,你会选择哪款?

在C语言中,全局变量滥用的后果是什么

01 啥是全局变量 说起全局变量,就不得不提到全局变量,局部变量,静态全局变量,静态局部变量,这些都....
发表于 2020-06-24 17:14 57次阅读
在C语言中,全局变量滥用的后果是什么

盘点一些在C语言中比较容易犯的错误

本题中的#运算符可以利用宏参数创建字符串。##运算符和#运算符一样也可以用于类函数宏的替换部分。另外....
发表于 2020-06-24 16:45 25次阅读
盘点一些在C语言中比较容易犯的错误

C语言的策略模式提高了程序的可维护性和扩展性

这里先插一点题外话,在C语言中,实现封装、继承、隐藏、多态等等特性,是完全没有问题的。但是在使用过程....
发表于 2020-06-24 16:29 42次阅读
C语言的策略模式提高了程序的可维护性和扩展性

从技术学习和实际运用的角度来看C/C++和Jav...

关于C语言和C++的学习路线终于梳理完了。当然我也只能从我曾经近3年的通信公司后台开发经历和目之所及....
发表于 2020-06-24 16:16 56次阅读
从技术学习和实际运用的角度来看C/C++和Jav...

c语言入门:c语言的具体结构

变量就是可以变化的量,而每个变量都会有一个名字(标识符)。变量占据内存中一定的存储单元。使用变量之前....
发表于 2020-06-23 15:38 252次阅读
c语言入门:c语言的具体结构

为什么要将C语言作为入门语言?

编程是向计算机发出指令以执行特定任务或执行指令的行为,目前专业行业和学术界使用数百种编程语言。一个人....
发表于 2020-06-23 15:13 110次阅读
为什么要将C语言作为入门语言?

大学生如何学习FPGA初学者怎么学FPGA

无论是从自身的发展,还是从FPGA所拥有的巨大市场来讲,学习FPGA都是一个不错的选择,对大家来说FPGA技术...
发表于 2020-06-23 15:12 240次阅读
大学生如何学习FPGA初学者怎么学FPGA

算法:计算Fibonacci number的六个...

算法:计算Fibonacci number的六个方法
发表于 2020-06-22 17:27 182次阅读
算法:计算Fibonacci number的六个...

C语言算法分析:求最长的递增数列

求最长的递增数列(Longest Increasing sequence, LIS)是一个比较常见的....
发表于 2020-06-22 14:57 142次阅读
C语言算法分析:求最长的递增数列

虚拟机:编译器对C函数的名字修饰

虚拟机:编译器对C函数的名字修饰
发表于 2020-06-22 11:44 240次阅读
虚拟机:编译器对C函数的名字修饰

详解C语言二分查找算法细节

我相信对很多读者朋友来说,编写二分查找的算法代码属于玄学编程,虽然看起来很简单,就是会出错,要么会漏....
发表于 2020-06-22 09:05 166次阅读
详解C语言二分查找算法细节

C语言:LeetCode 153寻找旋转排序数组...

假设按照升序排序的数组在预先未知的某个点上进行了旋转。
发表于 2020-06-22 08:59 118次阅读
C语言:LeetCode 153寻找旋转排序数组...

查找山脉数组最大值的三个方法

何为山脉数组?如果数组 A 是一个山脉数组的话,那它满足如下条件:
发表于 2020-06-22 08:51 133次阅读
查找山脉数组最大值的三个方法

C语言: Leetcode 33搜索旋转排序数组

假设按照升序排序的数组在预先未知的某个点上进行了旋转。
发表于 2020-06-22 08:51 119次阅读
C语言: Leetcode 33搜索旋转排序数组

C语言:leetcode 35搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会....
发表于 2020-06-22 08:40 110次阅读
C语言:leetcode 35搜索插入位置

探讨单片机C语言编程理论知识

编程思路和算法决定一个程序的优劣,是单片机编程的大问题,只有在实际动手编写的时候才会有深切的感悟。一....
发表于 2020-06-18 16:06 254次阅读
探讨单片机C语言编程理论知识

单片机C语言编程:.H文件与.C文件的关系

经过查找资料得知,.H文件就是头文件,估计就是Head的意思吧,这是规范程序结构化设计的需要,既可以....
发表于 2020-06-18 15:18 248次阅读
单片机C语言编程:.H文件与.C文件的关系

有人用过C语言位域吗

typedef struct {u16 b :5; u16 g :6; u16 r :5; } RGB; RGB *rgb; tx=0xf40f;      &n...
发表于 2020-06-16 04:35 34次阅读
有人用过C语言位域吗

知道C语言的用法但是avr里面并没有time这个头文件,是要用中断吗

知道C语言的用法但是avr里面并没有time这个头文件,是要用中断吗, 求大神神助解答 ...
发表于 2020-06-15 05:56 979次阅读
知道C语言的用法但是avr里面并没有time这个头文件,是要用中断吗

GPIOA->CRH&=0xFFFFFFFO什么意思呀?

问一下GPIOA->CRH&=0xFFFFFFFO什么意思呀?因为我是菜鸟刚看这个根本什么都不知道!!!...
发表于 2020-06-13 09:00 183次阅读
GPIOA->CRH&=0xFFFFFFFO什么意思呀?

C语言和ASM语言是怎么建立起来的联系呢?

在HVLLC主程序中,有如下定义 extern volatile long *ADCDRV_1ch_Rlt7; // Vout volatile long Vout; ...
发表于 2020-06-09 14:51 66次阅读
C语言和ASM语言是怎么建立起来的联系呢?

谁有嵌入式C语言入门视频教程

  本套C语言视频教程是星创客精英训练营的基础教程,由华清远见总监级讲师冯利美花了一个月的时间录制。经过后期音...
发表于 2020-06-08 04:35 55次阅读
谁有嵌入式C语言入门视频教程

c语言写代码是怎样组织文件的?

在用c语言写代码是大家是怎样组织文件的?一般都是一个.c配一个.h文件, 并且.c中放函数和变量定义,.h中放宏定义和函...
发表于 2020-06-05 03:20 42次阅读
c语言写代码是怎样组织文件的?

求最值的c语言程序问题

各位广大的坛友好: 先谢谢各位坛友! 本人最近初学c语言程序设计遇到了一个问题,程序如下所示: #include int ...
发表于 2020-06-02 20:52 263次阅读
求最值的c语言程序问题

C语言编程问题

我想问一下论坛的各位: 怎么用按键控制灯 按一下按键,第一个LED灯D1开始闪烁,闪烁5秒后常亮。但是如果在D...
发表于 2020-06-02 14:05 224次阅读
C语言编程问题