你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

C语言宏定义

[复制链接]
gaosmile 发布时间:2020-6-17 11:47
1 概述

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

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

  • 简单宏定义

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

#define 标识符 字符串

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

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

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

  • 程序会更易读。一个认真选择的名字可以帮助读者理解常量的意义;
  • 程序会更易于修改。我们仅需要改变一个宏定义,就可以改变整个程序中出现的所有该常量的值;
  • 可以帮助避免前后不一致或键盘输入错误;
  • 控制条件编译;
  • 可以对C语法做小的修改;
  • 带参数的宏

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

#define <宏名>(<参数列表>) <宏体>

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

算符优先级问题:

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

注意:

  • 预编译器只是进行简单的文本替换,COUNT(x+1)被替换成COUNT(x+1x+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) #param

char *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");
3
4 输出结果: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])))
收藏 评论2 发布时间:2020-6-17 11:47

举报

2个回答
ldptest 回答时间:2020-6-17 12:06:00
谢谢,宏定义好用。
lsfcrt 回答时间:2020-6-17 13:29:17
索嘎,,,,学到了

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版