宏是学习任何语言所不可缺少的,优秀的宏定义可以使得代码变得很简洁且高效,有效地提高编程效率。
宏是一种预处理指令,它提供了一种机制,可以用来替换源代码中的字符串,解释器或编译器在遇到宏时会自动进行这一模式替换
C语言有简单的宏系统,由编译器或汇编器的预处理器实现。C的宏预处理器的工作只是简单的文本搜索和替换,
C语言的宏非常简单,我们只需要做好宏定义,其余交给编译器预处理即可
1. 宏定义
2. 包含头文件的宏
3. 条件编译宏
4. 预定义宏
c程序提供的预处理功能之一。包括带参数的宏定义和不带参数的宏定义。具体是指用一个指定的标志符来进行简单的字符串替换或者进行阐述替换。形式为:
#define 标志符[(参数表)] 字符串
其中“#”表示这是一条预处理命令(在 C 语言中凡是以“#”开头的均为预处理命令)“define”为宏定义命令,“标识符”为所定义的宏名, “字符串”可以是常数、表达式、格式串等。符号常量的定义就是一种无参宏定义
常见使用
//宏定义
#define SIZE 1000
//取消宏
#undef SIZE
//普通宏
#define PI 3.1415926
//带参数的宏
#define max(a,b) ((a)>(b)? (a),(b))
其实宏定义就是一个简单的字符串替换,将前面的字符串替换成后面的字符串。
当然要注意,#define宏定义的作用仅仅是替换,它只是一个简单的替换,
比如下方代码:
#define m(a,b) a*3+b*4
c = m(5+6,2+4)
//C的结果等于41
这里的宏定义仅仅是将a换为5+6 而不是11 将b换位2+4 而不是6
因此顺序应该是 5+63+2+44 = 41
如果想要实际的预期结果 则需要
#define m(a,b) a*3+b*4
c = m((5+6),(2+4)) //应该使用括号将其包围
//C的结果等于57
再比如
#define point (int*);
point a,b;
本意是a和b都是int型指针,但是实际上变成int* a,b;
a是int型指针,而b是int型变量。
这点要尤为注意
宏连接:
C语言中,使用两个#即可将两个字符连接成为一个
#include
#define A1 printf("print A1\r\n")
#define A2 printf("print A2\r\n")
#define A(NAME) A##NAME
int main()
{
A(1);
return 0;
}
会打印:
print A1
在该例子中,调用宏A(1)时,NAME为1。A##NAME这个符号连接,即将A和1连接成了一个符号A1,然后执行宏A1的内容。最终打印出来了print A1
还有就是
无法通过宏展开的方式创建预处理器命令。即使宏的展开结果会生成形式上有效的命令,但预处理器不会执行它
你所要知道的小知识:
用一个include
表示,引入的头文件有两种区别
一种是C语言自带的头文件,用 <>
来表示
#include
编译的时候会在编译器的bin
目录下面查找
另一种是用户自定义头文件,用""
来表示
#include "LED.h"
编译时从对应自定义文件路径查找
当然 ,C语言自带头文件也可以使用 ""
这个我们讲解下:
“”
先在自定义路径查找有无该头文件,有则包含该目录下的头文件,没有则到系统指定的目录下找该头文件<>
直接到系统指定的目录下查找该文件也就是说使用双引号比使用尖括号多了一个查找路径
#include 引入头文件的本质就是源码替换,预处理的时候将那些.h文件中的代码替换到头文件引入的位置进行编译 比如printf就会从stdio.h中寻找对应源码,之后进行替换,再替换以后的结果再交给编译器处理,进行编译。
c语言中条件编译相关的预编译指令
#define 定义一个预处理宏
#undef 取消宏的定义
#if 编译预处理中的条件命令,相当于C语法中的if语句
#ifdef 判断某个宏是否被定义,若已定义,执行随后的语句
#ifndef 与#ifdef相反,判断某个宏是否未被定义
#elif 若#if, #ifdef, #ifndef或前面的#elif条件不满足,则执行#elif之后的语句,相当于C语法中的else-if
#else 与#if, #ifdef, #ifndef对应, 若这些条件不满足,则执行#else之后的语句,相当于C语法中的else
#endif #if, #ifdef, #ifndef这些条件命令的结束标志.
defined 与#if, #elif配合使用,判断某个宏是否被定义
#error 编译程序时如果遇到#error就会生成一个编译错误提示信息并停止编译
举个简单的例子:
#define ZZX
#ifdef ZZX
printf(“定义了Z小旋”);
#else
printf(“没有定义Z小旋”);
#endif
上面的代码就会输出定义Z小旋 而不满足条件的代码就不会编译
我们经常使用条件编译来定义头文件
#ifndef _DataCollect_H_
#define _DataCollect_H_
#代码块
#endif
条件编译再我们正常程序的编写中是非常见的,你可以使用条件编译完成模块不同功能的设置,比如你想要用一套代码编译一个产品的两个功能,使用条件编译,一个#ifndef 即可完成两个不同代码块的切换,决定编译的时候生成的是哪个功能的代码。
宏名称 | 功能 |
---|---|
_LINE_ | 正在编译的文件的行号 |
_FILE_ | 正在编译的文件的名字 |
_DATE_ | 编译时刻的日期字符串 |
_TIME_ | 编译时刻的时间字符串 |
_STDC_ | 判断该程序是否为标准的c程序 |
标准的预定义宏都是用一两个下划线字符开头和结尾,这类宏不能被#undef所取消也不能被编程人员重新定义和修改 ,常用来说明文件信息等
#include
int main() {
printf("Date : %s\n", __DATE__);
printf("Time : %s\n", __TIME__);
printf("File : %s\n", __FILE__);
printf("Line : %d\n", __LINE__);
system("pause");
return 0;
}
输出如下:
Date : Sep 28 2019
Time : 21:46:50
File : C:\Users\48013\Desktop\小学弟的渣渣c\预定义宏.c
Line : 6
剩余部分宏:
宏名称 | 功能 |
---|---|
_STDC_VERSION_ | 表示ISO C的版本 |
_STDC_HOSTED_ | 如果值为1的话,表示目标环境有完成的标准C库 |
_BYTE_ORDER_ | 表示当前环境的字节序 |
_LP64_ | 表示当前环境是不是64位,如果该值为1,则环境为64位环境 |