【C语言】15-预处理指令1-宏定义
预处理指令简介
一、不带参数的宏定义
1.一般形式
#define 宏名 字符串
比如#define ABC 10
右边的字符串也可以省略,比如#define ABC
2.作用
它的作用是在编译预处理时,将源程序中所有"宏名"替换成右边的"字符串",常用来定义常量。
接下来写个程序根据圆的半径计算周长

1 #include <stdio.h>
2
3 // 源程序中所有的宏名PI在编译预处理的时候都会被3.14所代替
4 #define PI 3.14
5
6 // 根据圆的半径计radius算周长
7 float girth(float radius) {
8 return 2 * PI *radius;
9 }
10
11 int main ()
12 {
13 float g = girth(2);
14
15 printf("周长为:%f", g);
16 return 0;
17 }

在第4行定义了一个叫PI的宏,在编译预处理之后,第8行中的2 * PI *radius就会变成2 * 3.14 * radius。
输出结果:
3.使用习惯与注意
1> 宏名一般用大写字母,以便与变量名区别开来,但用小写也没有语法错误
2> 对程序中用双引号扩起来的字符串内的字符,不进行宏的替换操作。比如:

1 #define R 10
2 int main ()
3 {
4 char *s = "Radio";
5 return 0;
6 }

在第1行定义了一个叫R的宏,但是第4行中"Radio"里面的'R'并不会被替换成10
3> 在编译预处理用字符串替换宏名时,不作语法检查,只是简单的字符串替换。只有在编译的时候才对已经展开宏名的源程序进行语法检查

1 #define I 100
2 int main ()
3 {
4 int i[3] = I;
5 return 0;
6 }

在做编译预处理的时候,不管语法对不对,第4行的I都会被替换为100。不过在编译的时候就会报第4行的错。

1 #define PI 3.14
2 /*
3 .
4 .
5 .
6 .
7 */
8 #undef PI

PI这个宏在第1行到第8行之间是有效的,第8行后就无效了
#define R 3.0
#define PI 3.14
#define L 2*PI*R
#define S PI*R*R
二、带参数的宏定义
1.一般形式
#define 宏名(参数列表) 字符串
2.作用
在编译预处理时,将源程序中所有宏名替换成字符串,并且将 字符串中的参数 用 宏名右边参数列表 中的参数替换

1 #include <stdio.h>
2
3 #define average(a, b) (a+b)/2
4
5 int main ()
6 {
7 int a = average(10, 4);
8
9 printf("平均值:%d", a);
10 return 0;
11 }

第3行中定义了一个带有2个参数的宏average,第7行其实会被替换成:int a = (10 + 4)/2;,输出结果为:。是不是感觉这个宏有点像函数呢?
3.使用注意
1> 宏名和参数列表之间不能有空格,否则空格后面的所有字符串都作为替换的字符串

1 #define average (a, b) (a+b)/2
2
3 int main ()
4 {
5 int a = average(10, 4);
6 return 0;
7 }

注意第1行的宏定义,宏名average跟(a, b)之间是有空格的,于是,第5行就变成了这样:
int a = (a, b) (a+b)/2(10, 4);
这个肯定是编译不通过的
2> 带参数的宏在展开时,只作简单的字符和参数的替换,不进行任何计算操作。所以在定义宏时,一般用一个小括号括住字符串的参数。
下面定义一个宏D(a),作用是返回a的2倍数值:
- 如果定义宏的时候不用小括号括住参数

1 #include <stdio.h>
2
3 #define D(a) 2*a
4
5 int main ()
6 {
7 int b = D(3+4);
8
9 printf("%d", b);
10 return 0;
11 }

第7行将被替换成int b = 2*3+4;,输出结果:
- 如果定义宏的时候用小括号括住参数,把上面的第3行改成:
#define D(a) 2*(a)
注意右边的a是有括号的,第7行将被替换成int b = 2*(3+4);,输出结果:
3> 计算结果最好也用括号括起来
下面定义一个宏P(a),作用是返回a的平方:
- 如果不用小括号括住计算结果

1 #include <stdio.h>
2
3 #define Pow(a) (a) * (a)
4
5 int main(int argc, const char * argv[]) {
6 int b = Pow(10) / Pow(2);
7
8 printf("%d", b);
9 return 0;
10 }

注意第3行,没有用小括号扩住计算结果,只是括住了参数而已。第6行代码被替换为:
int b = (10) * (10) / (2) * (2);
简化之后:int b = 10 * (10 / 2) * 2;,最后变量b为:
- 如果用小括号括住计算结果
将上面的第3行代码改为:
#define Pow(a) ( (a) * (a) )
那么第6行被替换为:
int b = ( (10) * (10) ) / ( (2) * (2) );
简化之后:int b = (10 * 10) / (2 * 2);,最后输出结果:。这个才是我们想要的结果。
也就意味着前面的#define average(a, b) (a+b)/2应该写成#define average(a, b) (((a)+(b))/2)
5.与函数的区别
从整个使用过程可以发现,带参数的宏定义,在源程序中出现的形式与函数很像。但是两者是有本质区别的:
1> 宏定义不涉及存储空间的分配、参数类型匹配、参数传递、返回值问题
2> 函数调用在程序运行时执行,而宏替换只在编译预处理阶段进行。所以带参数的宏比函数具有更高的执行效率
【C语言】15-预处理指令1-宏定义的更多相关文章
- VC中预处理指令与宏定义详解
刚接触到MFC编程的人往往会被MFC 向导生成的各种宏定义和预处理指令所吓倒,但是预处理和宏定义又是C语言的一个强大工具.使用它们可以进行简单的源代码控制,版本控制,预警或者完成一些特殊的功能. 一个 ...
- c语言的预处理指令分3种 1> 宏定义 2> 条件编译 3> 文件包含
宏简介 1.C语言在对源程序进行编译之前,会先对一些特殊的预处理指令作解释(比如之前使用的#include文件包含指令),产生一个新的源程序(这个过程称为编译预处理),之后再进行通常的编译 所有的预处 ...
- C语言 预处理二(宏定义--#define)
//#define 宏定义(宏定义一般大写) //知识点一-->#define的作用域:从#define开始,从上往下,如果遇到#undef就到#undef处结束,如果没有就是作用于当前整个文件 ...
- C语言的本质(19)——预处理之一:宏定义
我们在写代码时已多次使用过以"#"号开头的预处理命令.如包含命令#include,宏定义命令#define等.在源程序中这些命令都放在函数之外,而且一般都放在源文件的前面,它们称为 ...
- 从头开始-06.C语言中预处理指令
预处理指令 不带参数的宏定义: 格式: #define 宏名 值 作用:提高代码的可读性 在程序编译前把所有出现宏名标示的位置都替换为定义宏的时候,宏名后面的值 带参数的宏定义 格式 #define ...
- C语言的头文件和宏定义详解
原文链接:https://blog.csdn.net/abc_12366/article/details/79155540
- Linux C编程学习之C语言简介---预处理、宏、文件包含……
C的简介 C语言的结构极其紧凑,C语言是一种模块化的编程语言,整个程序可以分割为几个相对独立的功能模块,模块之间的相互调用和数据传递是非常方便的 C语言的表达能力十分强大.C语言兼顾了高级语言和汇编语 ...
- C语言-1.结构体,2.枚举,3.typedef,4.预处理指令的概念,5.条件编译
1. 结构体数组 定义:由若干个相同类型的结构体变量组成的有序的集合. 定义格式: 1) 定义结构体的同时定义结构体数组 struct Car{ int lunzi; int speed; }cars ...
- C语言include预处理命令与多文件编译
#include预处理命令几乎使我们在第一次接触C的时候就会碰到的预处理命令,可我现在还不怎么清楚,这次争取一次搞懂. 一.#include预处理指令的基本使用 预处理指令可以将别处的源代码内容插入到 ...
- 宏定义中的##操作符和... and _ _VA_ARGS_ _
1.Preprocessor Glue: The ## Operator 预处理连接符:##操作符 Like the # operator, the ## operator can be used i ...
随机推荐
- IDEA 14快捷键
1.ctrl+alt+左箭头.右箭头:返回到上次浏览的代码处(相当于Eclipse的alt+左右箭头) 编辑类: Ctrl+Space 基本代码实例(类.方法.变量) Ctrl + Shift + S ...
- 2.7 编程之美--最大公约数的3种解法[efficient method to solve gcd problem]
[本文链接] http://www.cnblogs.com/hellogiser/p/efficient-method-to-solve-gcd-problem.html [题目] 求两个正整数的最大 ...
- iOS 使用interface builder 创建太复杂的constrains时容易产生crash
今天写程序,遇到了crash,在界面初始化时不会有,想切换到别的tab页就报错了.主要内容如下: Cannot find an outgoing row head for incoming head ...
- Android 使用dip单位进行布局的一点知识
先看看怎么算出一个设备的dpi, 其实就是算出对角线上有多少个px,之后除上屏幕尺寸.比如,1280*720 的10.1寸设备,dpi = (sqrt(1280*1280+720*720)) / 1 ...
- c++ template函数的声明和实现需要在同一个文件中
新建一个class C;生成2个文件C.h和C.cpp,在C.h中声明一个函数 template<class T> T stringTo(char* str); 直接用VAssistX的R ...
- 删除自带OpenJDK
1:rpm -qa|grep jdk 查看当前的jdk情况. 2:yum -y remove java java-1.7.0-openjdk* 卸载openjdk,这个过程中因为依赖原因可能会卸载一些 ...
- Genesis自动登录方法(免输入用户名和密码)
第一步:点击“我的电脑”右键属性在“高级”里面的“环境变量”里面把“系统变量”照下图所示新建(XP和WIN7的环境变量设置方法类似): 变量名:FRONTLINE_NO_LOGIN_SCREEN 变量 ...
- Linux命令行下创建纳入版本控制下的新目录
[root@ok 资料库]# svn mkdir test A test [root@ok 资料库]# svn ci -m "mkdir test" Adding 资料库/test ...
- 《数学之美》(吴军 著)读书笔记:第1章 文字和语言 vs 数字和信息
第1章有4个小节,以及前言. 前言 1.信息 2.文字和数字 3.文字和语言背后的数学 4.小结 下面我一一展开,让我们看看每一节都说了什么. 前言 语言和数字都是信息传播的载体,他们之间其实存在着天 ...
- Windows中检测当前是否有窗口全屏
不时看到有人问起如何判断当前是否有窗口正处于全屏状态? 不过, 在解决这个问题之前先来解决一个简单的问题? 什么是全屏? 相当一部分人认为: 窗口如果是最大化的, 那么它就是最 ...