--C语言设置了预定义符号,直接使用(预处理符号在预处理阶段处理)。
__FILE__//进行编译的源文件
__LINE__//文件当前行号
__DATE__//文件编译的日期
__TIME__//文件编译的时间
__STDC__//若编译器遵循标准c,值为1,否则未定义//使用
int main()
{
printf("%s\n", __FILE__);
printf("%d\n", __LINE__);
printf("%s\n", __DATE__);
printf("%s\n", __TIME__);
return 0;
}
//基本形式
#define NAME STUFF
NAME:宏的名称,通常使用全大写字母和下划线来命名.(函数名不要全大写)
STUFF:替换体,代表将要替换 NAME 的任何文本。//例子
#define MAX 1000
#define reg register//register关键词,更简短的形式代替
#define do_forever for(;;)//替换死循环
#define CASE break;case //switch预语句,写case自动加上break
#define DEBUG_PRINT printf( "file:%s\t line:%d\t date:%s\t time:%s\n",\
__FILE__,__LINE__,\
__DATE__,__TIME__)--对于最后一条,原因代码太长,为了全部展现在要分行处的末尾紧跟着加 ' \ '(不能有空格)
--那为什么不在定义语句后面加分号?
#define MAX 1000
#define MAX 1000;--由于宏定义本身特点,会将STUFF出的内容全部展现,包括' ; ',可能导致语句出现两个分号,出现错误。


--#define机制包括一个规定,允许将参数替换到文本中,通常称为宏或定义宏。
//形式
#define NAME(parament-list) STUFF--( parament-list )是由逗号隔开的符号表,它们可能出现在stuff中。 --括号紧挨NAME,两者之间有任何空白存在,参数列表会被解释为stuff的一部分(相当与定义宏常量)。
--错误1:
#define SQUARE(x) x*x
int main()
{
int a = 5;
int ret1 = SQUARE(a);//25
//宏接受参数a-5,5*5再替换宏,得到ret1 = 25
int ret2 = SQUARE(a+1);//11
//为什么不输出36?
//接收后形式:a + 1 * a + 1;优先级——>先乘法,再加法
printf("%d\n%d\n", ret1, ret2);
return 0;
}--解决:
#define SQUARE(x) (x)*(x)
//先给宏定义文本个体加括号,解决优先级问题
int main()
{
int a = 5;
int ret1 = SQUARE(a);//25
int ret2 = SQUARE(a+1);//36
printf("%d\n%d\n", ret1, ret2);
return 0;
}--错误2:
#define DOUBLE(X) (X)+(X)
int main()
{
int a = 5;
int ret = 10 * DOUBLE(a);//55
//为什么不输出100?
//接收形式:10 * 5 + 5,又是优先级问题
printf("%d\n", ret);
return 0;
}--解决:
#define DOUBLE(X) ((X)+(X))
//文本整体再加括号
int main()
{
int a = 5;
int ret = 10 * DOUBLE(a);//100
printf("%d\n", ret);
return 0;
}--当宏参数在宏定义中出现超过一次时,若参数有副作用,那在用宏时可能出现危险,导致错误。副作用就是表达式求值的时候出现的永久性效果(改变了参数数值)。
//比如简单的+1操作
x + 1//正常
x++//副作用,改变了x值#include<stdio.h>
#define MAX(a,b) ((a)>(b)?(a):(b))
int main()
{
int x = 5;
int y = 8;
int z = MAX(x++, y++);
printf("x=%d y=%d z=%d", x, y, z);
return 0;
}副作用 --首先 z 经预处理后:z = ((x++) > (y++) ? (x++) : (y++));——>先比较x、y值。 --由于是后置操作,先使用在操作,x、y值都+1后进行——>x = 6,y = 9,z = 9。 --最后y在进行后置操作,y = 10。 (对于函数则是先计算完再传参)
--程序中拓展#define定义符号和宏时,有几个步骤:
--注意:
//解释字符串内容不被搜索
#define M 100
int main()
{
int ret = M;
printf("M:%d\n", M);
return 0;
}
输出:M:100--宏被应用于简单的运算:
//找出两值的较大值
#define MAX(a, b) ((a) > (b)?(a):(b))
int main()
{
int a = 6;
int b = 2;
int ret = MAX(a, b);
printf("MAX:%d\n", ret);
return 0;
}--为什么用宏?不用函数?
--劣势:
--对比表:
属性 | #define定义宏 | 函数 |
|---|---|---|
代码长度 | 每次使用,宏代码会插入到程序。除了非常小的宏外,程序长度被大幅增长 | 函数代码只出现一个地方;每次使用时,调用那地方的同份代码 |
执行速度 | 更快 | 存在函数的调用和返回的额外开销,相对慢 |
操作符优先级 | 宏参数的求值是在周围所有表达式的上下文环境里,除非加上括号,否则邻近操作符优先级会产生与预想不同,建议写宏时多写括号 | 函数参数只在函数调用时求值一次,结果值传给函数,表达式求值结果易预测 |
副作用参数 | 参数可能被替换到宏体中多个位置,若宏参数被多次计算,带有副作用的参数求值可能产生不可预料的结果 | 函数参数只在传参时求值一次,结果易控制 |
参数类型 | 宏参数与类型无关,只要对参数的操作是合法的,就可以用于任何类型 | 函数参数和函数类型有关,参数类型不同,需要不同函数,即使执行的任务是不同的 |
调试 | 不方便调试 | 可以逐语句调试 |
递归 | 不可以 | 可以 |
#C语言——学习攻略:攻克 文件操作内容(一),根本不在话下!
#C语言——学习攻略:攻克 文件操作内容(二),根本不在话下!
结语:本篇文章到此结束,对于C语言相关知识大家要多次回顾,如果这篇文章对你的学习有帮助的话,欢迎一起讨论学习,你这么帅、这么美给个三连吧~~~