预定义符号
c语言中设置一些预定的符号,我们可以直接使用
//列:
__FILE__ //进⾏编译的源⽂件
__LINE__ //⽂件当前的⾏号
__DATE__ //⽂件被编译的⽇期
__TIME__ //⽂件被编译的时间
__STDC__ //如果编译器遵循ANSI C,其值为1,否则未定义
/ 续行符号
int main()
{
printf("file = %s\nline = %d\ndate = %s\ntime = %s\n", \
__FILE__, __LINE__, \
__DATE__, __TIME__);
return 0;
}
#define 用法
//定义常量
#define max 100
int main()
{
printf("%d\n", max);
return 0;
}
//给关键字创建一个别的名称
#define i int
i main()
{
i a = 10;
printf("%d\n", a);
return 0;
}
我们平时使用代码时结尾都是以;,那么#define后面需不需要加上呢?
#define min 1;
#define max 1
int main()
{
printf("%d\n", min); //err
printf("%d\n", max);
return 0;
}
答案是不能因为在预处理阶段,编译器会删除所有的#define,并且替换定义的变量
拿上面的代码举例
下面是预处理替换后的代码
int main()
{
printf("%d\n", 1;);
printf("%d\n", 1);
return 0;
}
#define 定义宏 - 可以传入参数
//比如:
#define add(x) x * x
int main()
{
printf("%d\n", add(2 + 1));
return 0;
}
这段代码会输出多少?有木有小伙伴算的是9,毕竟3*3是9,那么这样就错了
下面我们一起来看看
首先我们前面了解到#define的内容会直接被替换
替换后
int main()
{
printf("%d\n", 2 + 1 * 2 + 1);
return 0;
}
// 根据优先级, 2+(1*2)+1 == 5
// 这种直接的替换往往也会带来一些小麻烦,要想解决也很容易,只要勤加()就行了
#define add(x) (x)*(x)
int main()
{
printf("%d\n", add(2 + 1));
return 0;
}
#endif
//这样就不用担心优先级带来的麻烦了
//这样就真的改好了吗,我们来看下面一段代码
#define add(x) (x)+(x)
int main()
{
printf("%d\n", 10 * add(5)); //我们想要的结果是100
return 0;
}
// 输出的确实55,这还是犯了与上面同样的问题,我们的()加少了
// 最好的方案是在外面一层也加上
#define add(x) ((x)+(x))
int main()
{
printf("%d\n", 10 * add(5));
return 0;
}
带有副作用的宏参数
举例:
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int main()
{
int a = 3;
int b = 10;
int z = MAX(a++, b++);
printf("%d\n %d\n %d\n", a, b, z);
return 0;
}
//由上面的函数我们来进行替换
int main()
{
int a = 3;
int b = 10;
int z = ((a++) > (b++) ? (a++) : (b++));
// 先执行(a++)>(b++) - a=4, b=11;
// 因为a<b, 所以执行表达式2(b++) - a=4,z=11,b=12
printf("%d\n%d\n%d\n", a, z, b);
return 0;
}
//这就是宏参数的副作用,如果换成函数又如何呢?
int fution(int a, int b)
{
return a > b ? a : b;
}
int main()
{
int a = 3;
int b = 10;
int z = fution(a++, b++);
printf("%d\n%d\n%d\n", a, z, b);
return 0;
}
//我们可以看见z的结果是10,而a,b的结果分别加了1,函数在传参后函数中a与b不再改变。
宏替换的规则
- 1.在调⽤宏时,⾸先对参数进⾏检查,看看是否包含任何由#define定义的符号。如果是,它们⾸先被替换。
- 2. 替换⽂本随后被插⼊到程序中原来⽂本的位置。对于宏,参数名被他们的值所替换。
- 3. 最后,再次对结果⽂件进⾏扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。
注意:
- 1. 宏参数和#define定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。
- 2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。
宏函数的对比
// 宏函数常常应用于比较简单的运算
// 如:比较大小
// 宏写
#define MAX(a, b) ((a)>(b)?(a):(b))
int main()
{
printf("%d\n", MAX(2, 3));
return 0;
}
// 函数写
int MAX(int a, int b)
{
return a > b ? a : b;
}
int main()
{
printf("%d\n", MAX(2, 3));
return 0;
}
为什么使用宏来运算而不使用函数
1. 相比较函数的调用,直接替换的计算工作时间更快
2. 宏与类型无关,你可以比较任意类型,然而函数却需要更改返回类型
宏函数的劣势
1.使用宏的时候,就相当于插入一段定义的代码,如果宏过长会导致代码太多,不好观察
2.宏无法调试
3.宏可能会带来优先级的问题,与类型也无关,不够严谨
#和##
#运算符
//#运算符
// #运算符所执行的操作可以将宏中的一个参数转换为字符串字面量
//如:我们有一个变量 int a = 20;
//我们想要使用宏然后打印出 the num of a is 20.
#define PRINT(n) printf("the num of "#n " is %d",n);
int main()
{
int a = 20;
PRINT(a);
return 0;
}
当我们按照下⾯的⽅式调⽤的时候:
PRINT(a);//当我们把a替换到宏的体内时,就出现了#a,⽽#a就是转换为"a",这时⼀个字符串
代码就会被预处理为:
printf("the num of "a " is %d",a);
##运算符
#define FUNTION_MAX(type) \
type type##_max(type a, tpye b)\
{ \
return (a > b ? a : b); \
}
// 这样使用后我们可以传入不同类型的参数了
命名约定
我们一般宏的使用命名时都全部大写,对于函数的应用却不全部大写
#undef
这条命令可以移除一个宏定义
#define MAX 100
int main()
{
printf("%d\n", MAX);
#undef MAX
printf("%d\n", MAX); //err
return 0;
}
条件编译
有时我们需要用一段代码,但用后后面可能还要使用,我们希望保留,并且设定一个开关,这就是条件编译
#define __DEBUG__
int main()
{
int i = 0;
int arr[10] = { 0 };
for (i = 0; i < 10; i++)
{
arr[i] = i + 1;
#ifdef __DEBUG__
printf("%d ", arr[i]);
#endif
}
return 0;
}
// 这样之后我们只有在前面定义 __DEBUG__ 我们才可以使用中间的代码
标签:__,main,return,int,C语言,printf,解析,预处理,define
From: https://blog.csdn.net/2301_81577798/article/details/137156522