本篇博客给大家带来的是#define定义常量和#define定义宏的方法
🐟🐟文章专栏:C语言
🚀🚀若有问题评论区下讨论,我会及时回答
❤❤欢迎大家点赞、收藏、分享
你们的支持就是我创造的动力
今日思想:本来就一无所有,何必瞻前顾后呢!
1、预定义符号
int main()
{printf("%s\n", __FILE__);//打印当前编译的源文件printf("%d\n", __LINE__);//代码的行号printf("%s\n", __DATE__);//文件编译的日期printf("%s\n", __TIME__);//文件被编译的时间printf("%d", __STDC__);//如果编译器遵循ANSIC则值为1,否则未定义return 0;
}
上面是C语⾔设置了⼀些预定义符号,可以直接使用,预定义符号也是在预处理期间处理的。
2、define定义常量
基本语法:
#define 名字 常量
例如:
#define M 10
变态代码1:
#define forever for(;;);
这个代码一旦被使用,永远不会执行下面的代码
变态代码2:
#define PRINT printf("the val of \
is %d\n",n);
注释:\是续行符。
上面的代码相当于:
printf("the val of is %d\n",n);
变态代码3:
#define CASE break;case
这个代码意思是:在写case语句的时候自动把break语句写上。
3、define定义宏
宏的基本语法:
#define name(parament-list) stuff
注意:参数列表的左括号必须与name紧邻,如果两者之间有任何空⽩存在,参数列表就会被解释为stuff的 ⼀部分。
代码实例:
#define DEV(n) n*nint main()
{int n = 10;int a = 4;printf("%d\n", DEV(n));printf("%d\n", DEV(a));return 0;
}
提示:#define DEV(n) n*n在预处理时会把使用DEV(n)的代码替换成n*n,上面代码替换之后会变成
这样:
#define DEV(n) n*nint main()
{int n = 10;int a = 4;printf("%d\n", n*n);printf("%d\n", a*a);return 0;
}
特殊情况:
#define DEV(n) n*nint main()
{int n = 10;int a = 4;printf("%d\n", DEV(n+1));printf("%d\n", DEV(a+1));return 0;
}
替换之后:
#define DEV(n) n*nint main()
{int n = 10;int a = 4;printf("%d\n", n+1*n+1);printf("%d\n", a+1*a+1);return 0;
}
得出的结果和想象的不一样
所以要在宏的参数部分加上括号,即:
#define DEV(n) ((n)*(n))int main()
{int n = 10;int a = 4;printf("%d\n", DEV(n+1));printf("%d\n", DEV(a+1));return 0;
}
注意:用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时由于参数中的操作符或邻近操作符之间不可预料的相互作用。
4、宏和函数的对比
函数实现加法:
//完成两个数的相加
int Add(int x, int y)
{return x + y;
}
int main()
{int n = 10;int a = 4;printf("%d\n", Add(n,a));//printf("%d\n", DEV(a));return 0
宏实现加法:
#define ADD(x,y) x+y
//完成两个数的相加int main()
{int n = 10;int a = 4;printf("%d\n", ADD(n,a));//printf("%d\n", DEV(a));return 0;
}
这两个方式都能实现加法,但是哪个更好呢???
使用宏的方式实现更好
原因如下:
1. 用于调⽤函数和从函数返回的代码可能比实际执行这个小型计算⼯作所需要的时间更多。所以宏比函数在程序的规模和速度方面更胜⼀筹。
2. 更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适⽤于整形、⻓整型、浮点型等可以用于 > 来比较的类型。宏的参数是类型无关的。
和函数相比宏的劣势:
1. 每次使用宏的时候,⼀份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序 的长度。
2. 宏是没法调试的。
3. 宏由于类型无关,也就不够严谨。
4. 宏可能会带来运算符优先级的问题,导致程容易出现错。
5、#和##号运算符
5.1、#号运算符
#运算符将宏的⼀个参数转换为字符串字面量。它仅允许出现在带参数的宏的替换列表中。 #运算符所执行的操作可以理解为”字符串化“。
代码示例:假如我们想打印the value of a is 10
#define PRINT(n) printf("the value of "#n " is %d", n);
int main()
{int a=10;PRINT(a);return 0;
}
预处理替换之后:
#define PRINT(n) printf("the value of "#n " is %d", n);
int main()
{int a=10;printf("the value of "a " is %d", n);return 0;
}
5.2、## 运算符
## 可以把位于它两边的符号合成⼀个符号,它允许宏定义从分离的文本片段创建标识符。 ## 被称为记号粘合
代码实例:
函数实现:
int int_max(int x, int y)
{return x > y ? x : y;
}
宏的实现方式:
#define GENERIC_MAX(type) \
type type##_max(type x, type y)\
{ \return (x>y?x:y); \
}
这两个代码一模一样
6、程序员的好习惯
宏的名字全部大小
函数名部分大写
7、undef
undef:用于移除一个宏定义
代码实例:
int main()
{int n = 10;int a = 4;printf("%d\n", ADD(n,a));//printf("%d\n", DEV(a));
#undef ADD(x,y) x+yprintf("%d\n", ADD(n, a));//会报错return 0;
}
8、条件编译
调试性的代码,删除可惜,保留⼜碍事,所以我们可以选择性的编译。
代码实例:
#define M 10
int main()
{#ifdef MAX//如果定义了M则打印haha,这句代码相当于#if define(MAX)printf("haha\n");#endif//注意:#ifdef和#endif配套使用,#endif我的理解是结束if语句#ifndef M//如果没有定义M就打印hei hei,相当于#if !define(M)printf("hei hei\n");#endif // !M//如果没有定义M就打印hei heireturn 0;
}
注意:这样的语句在预编译的时候会选择编译,上面的代码相当于:
#define M 10
int main()
{printf("haha\n");return 0;
}
还有这样的代码:
int main()
{int x = 10;int y = 20;
#if(x>y)printf("%d", x);
#elif(x==y)//相当于else ifprintf("%d", y);
#elseprintf("%d", y);
#endifreturn 0;
}
选择编译后:
int main()
{int x = 10;int y = 20;printf("%d", y);return 0;
}
9、头文件的包含
自己写的头文件用"",例如#include"name,h"
库里面的头文件用<>,例如#include<stdio.h>
自己写的头文件的查找文件:先在源文件所在⽬录下查找,如果该头文件未找到,编译器就像查找库函数头文件⼀样在标准位置查找头文件。 如果找不到就提示编译错误
库头文件的包含的查找方式:直接去标准路径下去查找,如果找不到就提示编译错误。
注意:其实库文件的包含也可以用"",但是比较费时间
如果包含连续包含一模一样的头文件会耗费代码运行的时间,我们可以这样做来防止这样的事例发生:
#pragma once
或者
#ifndef ___TEST_H__
#define<test.h>
#end
完!!!