目录
下一篇:c语言多个.c文件编译以及操作
宏定义
一、是什么?
编译预处理指令
#开头的是编译预处理指令
他们不是C语言的成分,但是C语言离不开它们
#define用来定义一个宏
//constdoublePI=3.14159;//c99的写法
//但是在更早的版本ANSI没有const可以用,用以下的形式
#definePI3.14159//定义一个叫PI的东西叫3.14159,也就是PI是这个宏的名字,3.14159是这个宏的值
intmain(intargc,charconst*argv[])
{
printf("%f\n",2*PI*3.0);
return0;
}
c语言在编译之前会做一次编译预处理,会把程序里所有的PI替换成后面的3.14159
使用gcc查看编译过程中的临时文件
gcc c_learn.c --save-temps
用这个命令保存编译过程中的临时文件
生成了以下这么多东西
真实的编译过程是.c->.i->.s->.o->a.out
我们用tail查看c_learn.i
会发现里面的PI全部替换成了3.14159
#define FORMAT "%f\n"
这个东西(字符串)都能换,就是纯粹的文本替换
特别注意:#define不能带分号; 因为这不是c的语句
二、这就是宏:
1、如果一个宏的值中有其他的宏的名字,也是会被替换的
2、如果一个宏的值超过一行,最后一行之前的行末需要加\
3、宏的值后面出现的注释不会被当作宏的值的一部分,空格等其他字符都会被当作宏的一部分
例子:
#define PI2 2*PI//pi*2这是注释
#define PRT print("%f",PI); \ //这是换行宏定义\
printf
#define PI 3.14159
#define PRT printf("%f\n",PI);\
printf("%f\n",PI*2)
int main(int argc,char const *argv[])
{
PRT;
return 0;
}
clion不能这么写,gcc可以这么写
三、没有值的宏
#define_DEBUG //用于告诉编译器,我们有了这个宏了
这类宏用于条件编译的,后面有其他的编译预处理指令来检查这个宏是否已经被定义过了
就是用来判断这个宏存在不存在,编译不同的分支代码
四、预定义的宏
_LINE_ 代表行号
_FILE_ 代表源代码文件名
_DATE_ 编译时候的日期
_TIME_ 编译时候的时间
_STDC_ 当它被定义后,编译器将按照ansic标准来编译你的c程序,这个东西不知道怎么用
都带"翅膀"
用来表达特殊的东西,让编译器替我们插入一些特殊的东西
测试
printf("%s:%d\n",__FILE__,__LINE__);
printf("%s:%s\n",__DATE__,__TIME__);
带参数的宏
一、像函数的宏
#define cube(x) ((x)*(x)*(x))
cube是立方
参数是没有类型的
宏可以带参数
同样前面是名字 后面是值
示例:
#define cube(x) ((x)*(x)*(x))
int main(int argc,char const *argv[])
{
printf("%d\n",cube(5));
return 0;
}
也就是填入在括号里的东西都会将x替换
int i=9;
printf("%d\n",cube(i*5));
也可以带变量进去
看似很方便
但是很容易犯错误
例如:
错误定义的宏
#define RADTODEG1(x) (x*57.29578)//弧度转化成角度
#define RADTODEG2(x) (x)*57.29578
int main(int argc,char const *argv[])
{
printf("%f\n",RADTODEG1(5+2));//我们以为是7*57.29578,结果是5+2*57.29578
printf("%f\n",180/RADTODEG2(1));//以为是180/(57.29578*1)结果是180/1*57.29578
归根结底还是因为括号里面的东西是直接粗暴的替换了x
所以有以下原则
一切都要括号
整个值要括号
参数出现的每个地方都要括号
改进:
#define RADTODEG2(x) ((x)*57.29578)
同样可以带多个参数
例如:
#define MIN(a,b) ((a)>(b)?(b):(a))
也可以组合(嵌套其他宏)
还有最后一定不要加分号
这种宏在大型程序代码中使用非常普遍
可以非常复杂,如"产生"函数
在#和##这两个运算符的帮助下
存在中西方文华差异(西方用的多,中方少)
部分宏(带参数的)会被inline函数替代,inline虽然是个函数但没有函数调用时的额外开销,且会参数类型检查
其他编译预处理指令
例如:
条件编译
error
…