宏
先了解程序执行的几个步骤:
1.预处理:
①将头文件展开
②宏替换
③条件编译
④去掉注释
2.编译:
①语义语法纠错
②将.c文件编译成汇编语言
3.汇编:将汇编语言变成二进制机器语言
4.链接:将所有的目标文件和依赖的库文件进行汇总,得到最终的可执行程序
一.宏的本质:文本替换
定义一个宏:
#define
移除一个宏:
#undef
二.宏的意义:
1.定义常量
2.定义类型
3.定义函数
例如:
(1)定义宏是否需要带分号
#define SIZE 5;
int a=SIZE;
//这就等价于
int a=5;;
int arr[SIZE]={ 0 };
//等价于
int arr[5;]={ 0 };
第一种只是多加了一个分号,只是多了一句空语句而已,没有语法错误
但是第二种定义数组的时候,多了一个分号就出现了语法错误。
(2)宏函数
//1.定义常量
#define MAX 100
//2.定义变量
#define uint unsigned int
//3.定义函数
#define ADD(a,b) a*b
但是,宏函数会经常出一些让人意想不到的错误。比如:
#define MUL(a,b) a*b
int b = MUL(10, 5 + 5);
printf("%d\n ", b);
我想得到的结果是:100
但是运行结果却是:55
这是因为宏的本质只是文本替换,上述代码的等价代码就是:
int a=10*5+5; //先进行乘法运算,所以结果是55
由于运算发优先级的问题我们可以采用加括号来修改。
4.宏的骚操作
(1)#替换字符串
例如:
#define PRINT(Val) printf(#Val " = %d\n", Val)
//期望打印的值是:
//10+20 = 30
PRINT(10+20);
//相当于
printf("10+20" " = %d\n", 10 + 20);
(2)##文本拼接
例如:
#define ADD_SUM(x,y) sum##x+=y
int sum1 = 10;
ADD_SUM(1, 2);
printf("%d\n", sum1);
此时,输出结果是这样的:
三.宏和函数
1.宏较于函数的优点:
①可以针对任何类型使用
②函数调用时开销较大(因为形参是实参的一份拷贝),而宏没有开销
2.宏较于函数的缺点:
①宏不能调试,函数可以调试
②宏没有参数类型的检查。
③宏不支持递归
④由于宏的本质是文本替换,所以可能会导致表达式求值时运算符的顺序不能只按照预期进行匹配
条件编译
1.格式:
1.
#if 常量表达式
//……
#dndif
2.分支条件编译语句
#if 常量表达式
//……
#else
//……
#endif
3.判断是否被定义
//如果symbol这个宏已经被定义,就执行其下面的语句
//两种写法等价
#if defined (symbol)
#ifdef symbol
//如果symbol这个宏没有被定义,再执行其下面的语句
//两种写法等价
#if !defined (symbol)
#ifndef
例:
#if defined n
int sum1 = 10;
ADD_SUM(1, 2);
printf("%d\n", sum1);
#else
printf("heheh!!!\n");
#endif
分析:含义是:如果n这个宏已经被定义,就执行下面直到else的语句,否则就执行else下面的语句。
注意:
if后面的条件要保证是编译时期有值的
2.防止头文件重复包含
法一:
#pragma once //使用该宏可以避免头文件被重复包含
法二:
//入头文件是:test.h
#ifdef TEST_H
#define TEST_H
//头文件内容
#endif
我们一般都使用法一来表面头文件的重复包含。
使用法二,如果头文件名重复那么还是起不到作用。
版权声明:本文为Wz_still_shuai原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。