在C语言中,我们使用#define来定义宏。在C程序编译的预处理阶段,预处理器会把宏定义的符号替换成指定的文本。

不带参数的宏

关于宏最常见的就是用来定义数值常量的名称,即没有参数的宏定义,采用如下形式:

1#define 宏名称    替换文本

例如:

1#define ARRAY_SIZE    10
2int data[ARRAY_SIZE];

当程序需要修改数组长度时,只需要修改宏定义即可,无需对程序中每一处用到数组长度的地方进行修改。

带参数的宏

你可以定义具有形参的宏,然后预处理器展开这类宏时,会将宏指定的实参替换文本中对应的形参。这有点像函数,故也叫做函数式宏定义、类函数宏,形式如下:

1#define 宏名称([行参列表]) 替换文本
2#define 宏名称([行参列表,]...)    替换文本

当宏被调用时,替换文本中的每个值都与形参列表相对应。另外C99标准允许定义有参略号的宏,省略号必须放在参数列表的后面,以表示可选参数。

当调用有可选参数的宏时,预处理器会将所有可选参数连同分隔它们的逗号打包在一起作为一个参数。在替换文本中,标识符 __VA_ARGS__对应前面打包的可选参数。

1//假设有个已经打开的日志文件,准备采用文件指针fp_log对其进行写入
2#define printLog(...) fprintf(fp_log, __VA_ARGS__)
3//使用printLog
4printLog("%s: intVar=%d\r\n", __func__, intVar);

预处理器把最后一行的宏调用替换成下面一行代码:

1fprintf(fp_log, "%s: intVar=%d\r\n", __func__, intVar);

带参宏的一些问题

1#include
2#define SQUARE(x)   x * x
3int main(int argc, char const *argv[])
4{
5    int a = 5;
6    printf("%d\r\n", SQUARE(5));
7    printf("%d\r\n", SQUARE(a+1));
8    return 0;
9}

程序运行,第一条打印显而易见为25,第二条打印为多少呢?不是36而是11。我们通过"gcc -E a.c >a.txt",将预处理后的文件重定向到a.txt,来观察被替换的宏文本。

1printf("%d\r\n", 5 * 5);
2printf("%d\r\n", a+1 * a+1);

可见替换产生的表达式并没有按照预想的次序进行求值。可能大家会说,加上两个括号就解决了嘛:

1#define SQUARE(x)  (x) * (x)

那么,为每个出现在替换文本中的参数加上括号就一定没问题了吗?看下面例子:

1#include
2#define ADD(x)    (x) + (x)
3int main(int argc, char const *argv[])
4{
5    int a = 5;
6    printf("%d\r\n", 10 * ADD(5));
7    return 0;
8}

看似输出100,实际输出55。我们看下替换后的文本:

1printf("%d\r\n", 10 * (5) + (5));

乘法运算在加法运算之前执行,所以结果为55。这个错误很容易修正:整个表达式加上括号:

1#define ADD(x)    ((x) + (x))

所有对数值表达式进行求值的宏定义,为避免参数中操作符或邻近的操作符之间不可预料的互相作用,应对每个参数加括号,整个表达式也要加括号。

宏与函数

尽可能多的加括号就绝对不会有问题了吗?看下面例子:

 1#include 2#define MAX(a, b)    ((a) > (b) ? (a) : (b))3int main(int argc, char const *argv[])4{

深入浅出讲解C语言#define宏定义应用及使用方法相关推荐

  1. 大牛深入浅出讲解C语言#define宏定义应用及使用方法

    在C语言中,我们使用#define来定义宏.在C程序编译的预处理阶段,预处理器会把宏定义的符号替换成指定的文本. 不带参数的宏 关于宏最常见的就是用来定义数值常量的名称,即没有参数的宏定义,采用如下形 ...

  2. 关于C语言define宏定义字符串常量

    1.问题由来: 本人一直以为宏对于字符串的处理也是直接在预处理时进行替换:但是最近在工作中遇到了字符串宏+1的情况:于是彻底的颠覆了以前的思维:于是乎进行测试验证得出以下结果. 2.测试代码 /*测试 ...

  3. C语言#define宏定义可能注意不到的地方

    #define使用的核心:直接替换 我也觉得自己很清楚这一点,但看到这一道输出程序片段结果题,还是懵了.大家也可以在不看我下方答案的情况下,自己做一下,题目如下: #include<stdio. ...

  4. c语言解除宏定义_C语言宏定义 define,及一些陷阱!

    https://m.toutiaocdn.com/group/6584292311289561607/?iid=39362926900&app=news_article&timesta ...

  5. c语言中宏定义的字符替换#define M(x,y,z) x*y+z

    C语言中宏定义的字符替换问题 例子: 在c语言中定义如下宏 #define M(x,y,z) x*y+z 给定如下程序 #include<stdio.h> #include<stdl ...

  6. 关于C语言刷题(#define宏定义函数的常见错误)

    关于C语言刷题(#define宏定义函数的常见错误) 首先我们来先看对#define的定义 define,宏定义,C语言中预处理命令一种.分为无参宏定义和带参宏定义.无参宏定义的一般形式为:#defi ...

  7. C语言基础知识之define宏定义表达式,undef,内存对齐,a和a的区别,数组知识点,int (*)[10] p,二维数组参数与二维指针参数,函数指针数组,常见的内存错误及对策

    一.用define宏定义表达式 1.定义一年有多少秒: #define SEC_A_YEAR 60*60*24*365 //上述描述不可靠,没有考虑到在16位系统下把这样一个数赋给整型变量的时候可能会 ...

  8. 【C语言】----宏定义,预处理宏

    什么是宏? 宏是学习任何语言所不可缺少的,优秀的宏定义可以使得代码变得很简洁且高效,有效地提高编程效率. 宏是一种预处理指令,它提供了一种机制,可以用来替换源代码中的字符串,解释器或编译器在遇到宏时会 ...

  9. 如何用C语言改变宏定义的大小,C语言中宏定义使用的小细节

    C语言中宏定义使用的小细节 #pragma#pragma 预处理指令详解 在所有的预处理指令中,#Pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作.#p ...

最新文章

  1. c# 使用线程方式实现消息订阅
  2. 英特尔人工智能副总裁:AI不是一种技能,而是一种对于工作的描述
  3. 全球唯一:MySQL社区2018年度公司贡献奖颁给阿里云
  4. OSG造成屏幕闪烁,且鼠标不能操作的一行代码
  5. 发现2017年最好的CSS框架
  6. Android 应用开发(18)---在运行时请求权限
  7. 苹果新功能惹众怒,4000多家组织和个人签署公开信 敦促苹果放弃“儿童安全”功能...
  8. 是什么让 Python 如此多才多艺?
  9. Git - 操作指南
  10. VSCode Python解决 No module named 问题
  11. WdatePicker—WdatePicker日历控件使用方法
  12. C++用I love you!打印心形
  13. 软件测试难不难?不是计算机专业也能学吗?
  14. bug解决 2021-09-20 build之后出现shader消失的原因之一
  15. 【推荐】1657- 灵活可扩展,2023年值得尝试的13款富文本编辑器
  16. Excel 下拉多选的设置
  17. 解决Couldn‘t determine repo type for URL
  18. linux系统下查看服务器的型号等信息
  19. Symantec 赛门铁克系列软件清除工具
  20. 信息孤岛影响_国内企业的痛点,“企业信息孤岛”怎么破?

热门文章

  1. 在硒中按TagName定位元素
  2. 在Gradle中为JPMS构建Java 6-8库
  3. 了解自定义De / Serializer:JSON绑定概述系列
  4. 在Java 9中使用sun.misc.Unsafe
  5. Lambda的Lambda(如果可选)
  6. resteasy_RESTEasy教程第1部分:基础
  7. 使用Java中的FileChannel和ByteBuffer在文件中读取/写入文件
  8. Java Swing模型视图适配器介体
  9. PrimeFaces Mobile入门
  10. 如何以10倍速加速Apache Xalan的XPath处理器