【预定义】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,以及符号#,##的相关运用已经有了一定认识,如果你感觉这期博客对你有帮助的话,请不要吝啬你们的点赞收藏和关注哦
【预定义】C语言预定义代码(宏、条件编译等)内容介绍【最全的保姆级别教程】的更多相关文章
- 预定义宏,C语言预定义的宏详解
1.预定义宏 对于预定义宏,相信大家并不陌生.为了方便处理一些有用的信息,预处理器定义了一些预处理标识符,也就是预定义宏.预定义宏的名称都是以"__"(两条下划线)开头和结尾的,如 ...
- visual c++中预定义的宏
一.主要目标 (由于visual studio通常包含很多开发环境,通常将其中c/c++的ide称为visual c++ 20xx) 整理下visual c++ 2010下预定义的宏.做一下备忘和了解 ...
- VS2013 预定义的宏
Visual Studio 2013 预定义的宏 https://msdn.microsoft.com/zh-cn/library/b0084kay(v=vs.120).aspx 列出预定义的 ANS ...
- 2019-8-31-dotnet-新项目格式与对应框架预定义的宏
title author date CreateTime categories dotnet 新项目格式与对应框架预定义的宏 lindexi 2019-08-31 16:55:58 +0800 201 ...
- dotnet 新项目格式与对应框架预定义的宏
在 sdk style 的项目格式支持使用多框架开发,此时需要在代码里面通过宏判断,在编译的时候执行不同的代码.本文告诉大家在框架里面对应的预定义的条件编译符有哪些 在让一个 csproj 项目指定多 ...
- gcc中预定义的宏__GNUC__
转载:gcc中预定义的宏__GNUC__ - Cccarl - 博客园 (cnblogs.com) 今天在看Linux系统编程这本书的代码的时候看到了__GNUC__,不太清楚这个宏所以去查了一下,以 ...
- C标准中一些预定义的宏
C标准中指定了一些预定义的宏,对于编程经常会用到.下面这个表中就是一些常常用到的预定义宏. 宏(双下滑线) 意义 __DATE__ 进行预处理的日期(“Mmm dd yyyy”形式的字符串文字) __ ...
- C标准中一些预定义的宏,如__FILE__,__func__等
C标准中一些预定义的宏 C标准中指定了一些预定义的宏,对于编程经常会用到.下面这个表中就是一些常常用到的预定义宏. 宏 意义 __DATE__ 进行预处理的日期(“Mmm dd yyyy”形式的字符串 ...
- ARM编译器中预定义的宏
arm系列目前支持三大主流的工具链,realview的armcc,iar ewarm的iccarm,gnu的gcc,编译器在编译的时候会预定义一些宏,这些宏在工程中起到不可或缺的作用. 例如 /* d ...
- C语言:预定义的宏
预定义宏就是已经预先定义好的宏,我们可以直接使用,无需再重新定义.ANSI C 规定了以下几个预定义宏,它们在各个编译器下都可以使用: __LINE__:表示当前源代码的行号: __FILE__:表示 ...
随机推荐
- BZOJ 3450 - Tyvj1952 Easy (期望DP)
描述 某一天 WJMZBMR 在打 osu~~~ 但是他太弱逼了,有些地方完全靠运气:( 我们来简化一下这个游戏的规则: 有 \(n(n\le 300000)\) 次点击要做,成功了就是 o,失败了就 ...
- Problem B - Card Constructions (构造)
题意: 你可以用图示的方法建造金字塔,但是每一次都要建最大的金字塔,问最后能建几个金字塔. 思路: 我们可以发现对于每一个金字塔都是两边增加了两天边,然后中间行数− 1 -1−1个三角形,所以就可以求 ...
- 【每日一题】35. [CQOI2009]中位数图 (前缀和,贡献值计算)
补题链接:Here 算法涉及:前缀和,贡献值计算 经典中位数计数问题,记得以前百度之星也出过类似的题,这道题有一个限定范围是要奇数区间的 我们很容易想到,奇数下标到偶数下标或者偶数下标到奇数下标的长度 ...
- 探究Presto SQL引擎(2)-浅析Join
作者:vivo互联网技术-Shuai Guangying 在<探究Presto SQL引擎(1)-巧用Antlr>中,我们介绍了Antlr的基本用法以及如何使用Antlr4实现解析SQL查 ...
- 新手学习VUE——环境搭建及创建项目
第一种方式: 1. 下载安装node.js 检查是否成功:node-v或npm-v 2..搭建项目: 第一种方法:用iview脚手架建项目 打开iview官网==>生态 ===>i ...
- freeswitch两个DTMF转换接口的区别
概述 freeswitch支持三种模式的DTMF传输方式,分别时inband.INFO.2833. 在传统的PSTN网络中,所有的DTMF码都是inband模式,所以VOIP网络和PSTN网络对接中, ...
- 小技巧:WIndows快速创建文件夹
快速创建文件夹的技巧 1.首先创建文本文档将扩展名更改为.bt,mkdir.bat 2.写入创建文件夹的代码 md 文件夹1 文件夹2 文件夹3 pause 3.双击执行mkdir.bat
- 【C++】类概念及使用
类定义中不允许对数据成员初始化 类外只能访问公有部分 类成员必须指定访问属性 类的成员函数是实现对封装的数据成员进行操作的唯一途径 类定义中不允许定义本类对象,因无法预知大小 类与结构形式相同,唯一区 ...
- 2023强网拟态crypto-一眼看出
1.题目信息 一眼看穿 查看代码 from Crypto.Util.number import * from secret import flag import gmpy2 flag=b'' r = ...
- 微信小程序——如何获取url中的数据
如何获取url中的数据 这里举个例子! 当我们需要编辑一个可以点击的图片超链接 这时候结构是这个样子的 首先最外层有一个视图层view 在view中添加超链接标签<navigator> & ...