【预定义】C语言预定义代码(宏、条件编译等)内容介绍【最全的保姆级别教程】

浅谈C语言预定义中的预定义符号,#define,以及符号#,##的相关运用
求个赞求个赞求个赞求个赞 谢谢🙏

先赞后看好习惯 打字不容易,这都是很用心做的,希望得到支持你 大家的点赞和支持对于我来说是一种非常重要的动力 看完之后别忘记关注我哦!️️️
本章节对于初学者来说,是比较简单的,而且我个人认为也非常的有趣,我相信大部分的小伙伴都可以理解

强烈建议本篇收藏后食用~

预定义符号的介绍

一下这些符号是不需要#define来进行定义的,是本身就定义好我们可以直接使用的符号。

__FILE__;进行编译的源文件
__LINE__;文件当前的行号
__DATE__;文件被编译的日期
__TIME__;文件被编译的时间
__STDC__;如果编译器遵循ANSI C,则其值为1,否则未定义
__FUNCTION__;当前运行的函数

我们可以输入程序打印出来看看

int main()
{
	printf("%s\n", __FILE__);
	printf("%d\n", __LINE__);
	printf("%s\n", __DATE__);
	printf("%s\n", __TIME__);
	printf("%s\n", __FUNCTION__);
	return 0;
}

在这里插入图片描述

我们可以依次看到,文件的位置,当前的行数,编译的日期,时间,当前的函数
有了这些,我们就可以在写代码的同时写日志了

int main()
{
	int i = 0;
	FILE* pf = fopen("log.txt", "a+");//追加的形式输入
	if (pf == NULL)//判断文件是否打开成功
	{
		perror("fopen\n");
		return 1;
	}
	for (i = 0; i < 10; i++)
	{
		fprintf(pf, "%s %d %s %s %d\n", __FILE__, __LINE__, __DATE__, __TIME__, i);
		//将我们的写代码时的信息存入log.txt这个文件里面
	}
	return 0;
}

在这里插入图片描述
这样,我们就可以把我们想要记录的信息存放到文件中了

#define的使用

#define定义符号

只要学过程序环境以及编译过程的伙伴,对#define所执行的方式都不陌生
#define所定义的符号,在预处理过程中就会被直接替换到函数里面。

#define M 1000;
#define reg register
#define do_forever for(;;)
int main()
{
	reg int num = 0;
	do_forever;//替换,变成了死循环了
	int m = M;///在预处理过程,M已经被替换成1000了
	printf("%d\n",m);
	return 0;
}

#define因为是直接替换,所以利用#define来定义常量在实现一些游戏程序的时候是很方便的,比如,我们写一个三子棋,(或者扫雷),我们需要定义二维数组,此时,我们可以直接定义char board[3][3]={0};,如果这样创建数组,以后每一次我们使用这个数组定义新函数的时候,我们都要输入这个3和3,如果有一天我想要把三子棋改成五子棋,那么我们修改的工作量就会比较大。
因此,我们可以使用#define语句来定义常量

#define ROW 3
#define COL 3
int main()
{
    char board[ROW][COL]={0};
    //.....实现过程
    return 0;
}

这样我们以后修改的时候,只需要修改#define时候的数字就可以了

#define定义宏

我们先来看一个简单的用法

#define SQUARE(X) X*X
int main()
{
    int a=3;
    int ret=SQUARE(a);
    printf("%d",a);
    return 0;
}

这样我们得到的结果是9,这种用法其实也是直接替换,将X*X替换成SQUARE(X),所以答案是9

注意:#define定义的宏是直接的替换,不会做任何的运算,下面我们来看两个例子

#define SQUARE(X) X*X
#define DOUBLE(X) (X)+(X)
int main()
{
	printf("%d\n", SQUARE(3+1));
	//注意:宏是直接完全替换的,而不会去搞计算
	//上面这一句等同于下面这一句--完全的直接的替换
	printf("%d\n", 3 + 1 * 3 + 1);
	//所以结果是7
	//替换是在预处理阶段就完成的,而计算结果是在运行的时候
	//想要得到16,我们可以这样写
	//#define SQUARE(X) ((X)*(X))
	//这样写才是最严谨的
	//写宏的的时候,括号很重要,但是有时候括号也会带来问题
	printf("%d\n", 10 * DOUBLE(4));//这里是得不到八十的
	printf("%d\n", 10 * (4) + (4));
	return 0;
}

很多小伙伴都误认为第一题是16,第二题是80,通过我写的注释我们可以得知,这个替换是直接进行的,不会进行运算
因此第一题变成了3+1*3+1,结果当然不是16,第二题同理。

以下也是一种用法

#define MAX(X,Y) ((X)>(Y)?(X):(Y))
int main()
{
	int max = MAX(101, 100);
	//跟函数传参完全不同,这里是替换进去
	return 0;
}

//注意:宏参数和#define定义中可以出现其他#define定义的变量。但是对于宏,不能出现递归
//      当预处理器搜索#define定义的符号的时候,字符串常量的内容不被搜索

#undef的使用

作用:取消定义

#define M 100
int main()
{
	int a = M;
#undef M
	//取消定义M
	printf("%d\n", M);//这里就编译不出来了
	return 0;
}

条件编译

条件编译
在编译一个程序的时候我们如果要将一条语句(一组语句)编译或者放弃是很方便的
因为我们有条件编译指令
调试性的代码,删除可惜,保留又碍事,所以我们可以选择性的编译

基本格式#(条件编译类型)...代码...#endif
每一种类型的条件编译后面的要跟上一个#endif,表示条件编译的范围

#ifdef和#undef

#ifdef:判断是否被定义
#ifndef:判断是否不被定义

我们看一段代码就明白了

#define PRINT
int main()
{
#ifdef PRINT//如果PRINT被定义了,才会编译,否则不会
	printf("hehe\n");//所以这里是会编译的
#endif
	//如果ifdef为假,在预处理阶段就删掉了
#ifndef HEHE
	printf("hehe\n");//因为ifndef没有被定义,所以此语句会被编译
#endif
	return 0;
}

同样,以下这种写法和上面这种是等价的

#if defined(TEST)//这种跟第一种是一样的
	printf("test2\n");
#endif
#if !defined(HEHE)
	printf("hehe2\n");
#endif
	return 0;
}

#if,#elif,#else的使用

这些语句的运用和我们在语句中的if,else if ,else是一样的,原理非常简单,我们看一段代码就明白了

//常见的条件编译指令
int main()
{
#if 0//如果#if后面的表达式为真,就编译
	printf("hehe\n");
#endif
	return 0;
}
//多个分支的条件编译
int main()
{
#if 1==1
	printf("hehe\n");
#elif 1==2
	printf("haha\n");
#else
	printf("heihei\n");
#endif
	return 0;
}

#符号的使用

我们先来看以下这个场景

int main()
{
    int a=10;
    int b=20;
    int c=30;
    //现在想要打印三句话
    printf("the value of a is %d\n",a);
    printf("the value of b is %d\n",b);
    printf("the value of c is %d\n",c);
    //这样写的话我们的the value of...is这些语句就重复写了三次
    return 0;
}

这样写的话我们的the value
of…is这些语句就重复写了三次,那么有没有什么更简单的方法?这时候,很多小伙伴都会想,我们可以使用函数,传参不就好了?但事实上操作起来,函数实现是非常麻烦的,因为the
value of后面这个字符是会变的,不相信的小伙伴可以使用函数做一些尝试。 因此这个时候我们就可以利用#这个操作符来帮助我们完成

#define PRINT(X) printf("the value of "#X" is %d\n",X);
//                                     ^此#非前面的#
//                                     ^此处如果没有#,就会被替换,代码就会出错了
//但是如果加上#,就不是替换了,#X就会变成X的内容所对应的字符串
int main()
{
	int a = 10;
	PRINT(a);//这一句跟下面这一句是完全等价的
	printf("the value of ""a"" is %d\n", a);
	int b = 20;
	PRINT(b);
	printf("the value of ""b"" is %d\n", b);
	int c = 30;
	PRINT(c);
	printf("the value of ""c"" is %d\n", c);
	return 0;
}

通过这种方式,我们就可以只是用三个PRINT()就可以完成我们的任务了
注意:定义宏的时候,两个字符串中间的X如果不加上#,就会被直接替换,这样的话代码是会出问题的
但是,如果我们加上#,就不是直接替换了,#X就会变成X的内容所对应的字符串

这样,我们就能很好的实现我们的功能
如果有不同类型的数据,我们还可以稍微优化一下我们的代码

//我们还可以把上面的代码稍微优化一下
//#X这个#只能在宏上面用
#define PRINT(X,FORMAT) printf("the value of "#X" is "FORMAT"\n",X)
int main()
{
	int a = 10;
	PRINT(a, "%d");
	int b = 20;
	PRINT(b, "%d");
	int c = 30;
	PRINT(c, "%d");
	float f = 5.5f;
	PRINT(f, "%f");
	return 0;
}

注意,#X只能在宏上使用

##符号的使用

个人认为,这个符号完成的算是个比较有趣的功能
它可以把两个符号连成一个符号

#define CAT(X,Y) X##Y
//可以把两个符号连成一个符号
int main()
{
	int grade9 = 100;
	printf("%d\n", CAT(grad, e9));
	//这里的CAT是直接把grad和e9连起来,所以打印的当然是100
	return 0;
}

尾声

看到这里,相信你对预定义中的与定义符号,#define,以及符号#,##的相关运用已经有了一定认识,如果你感觉这期博客对你有帮助的话,请不要吝啬你们的点赞收藏和关注哦

posted @ 2021-11-02 00:25  背包Yu  阅读(11)  评论(0编辑  收藏  举报  来源