jjzjj

【C语言进阶】还说不会?一文带你全面掌握计算机预处理操作

銮崽的干货分享基地 2025-02-02 原文

目录

🍊前言🍊:

🍈一、宏与函数🍈:

        1.宏与函数对比:

        2.宏与函数的命名约定:

🍓二、预处理操作符🍓:

        1.预处理操作符 " # ":

        2.预处理操作符 " ## ":

🥝三、条件编译🥝:

        1.简述条件编译指令:

        2.常见条件编译指令:

🍒总结🍒:


🛰️博客主页:✈️銮同学的干货分享基地

🛰️欢迎关注:👍点赞🙌收藏✍️留言

🛰️系列专栏:💐【进阶】C语言学习

                       🧧  C语言学习

🛰️代码仓库:🎉VS2022_C语言仓库

        家人们更新不易,你们的👍点赞👍和⭐关注⭐真的对我真重要,各位路过的友友麻烦多多点赞关注,欢迎你们的私信提问,感谢你们的转发!

        关注我,关注我,关注我,你们将会看到更多的优质内容!!


🏡🏡 本文重点 🏡🏡:

🚅 宏与函数 🚃 预处理操作符 🚃 条件编译🚏🚏

🍊前言🍊:

        在上节课中,我们对程序编译的环境、编译链接过程以及很重要的预处理指令 #define 进行了研究,对于程序的预处理过程有了一定的了解,而这节课我们将要继续学习预处理的一些相关知识,帮助我们更加全面的掌握程序的预处理过程。

🍈一、宏与函数🍈:

        1.宏与函数对比:

        我们之前在使用宏 #define 时,常用于定义一些全局的宏常量等。而现在我们要知道的是,宏还常常被应用于执行简单的运算,例如比较两数的大小我们可以这样用:

#define MAX(a,b) ((a)>(b)?(a):(b))

#include<stdio.h>
int main()
{
	int a = 5;
	int b = 10;
	printf("MAX = %d\n", MAX(a, b));
	return 0;
}

        那么可能有的小伙伴就会问了,那为什么我们不使用函数来完成这个过程呢

★ 在这里使用宏而不用函数的主要原因有两个:

①. 相比于函数宏在程序规模与速度方面更胜一筹:由于函数在调用时牵扯到函数栈帧的创建与销毁等操作,所以用于调用函数以及从函数返回的耗时可能比实际执行这个小型计算工作的耗时更多

②. 宏是类型无关的:更重要的是我们都知道,在声明、定义和使用函数时,函数的参数必须是特定的类型,所以函数只能在类型合适的特定表达式上使用。反观宏,无论是整形、长整型还是浮点型,都可以进行比较

        但是我们说宏也有缺点

★ 当然宏与函数相比也有劣势:

①. 宏只能处理简单运算:我们知道在预处理阶段宏将会进行符号替换,这就意味着每次在使用宏的时候,一份宏定义的代码将插入到程序中。这样一来,如果宏比较长,就将会大幅度增加程序代码的长度

②. 宏是没有办法进行调试的

③. 由于宏具有类型无关的特点,因此也不够严谨

④. 宏可能会带来运算符优先级的问题,导致程序容易出错。

        可是,宏也可以做到函数做不到的事。比如在宏中可以出现类型,而函数不可以

#define MALLOC(num,type) (type*)malloc(num*sizeof(type))

#include<stdio.h>
#include<string.h>
int main()
{
	MALLOC(10, int);
	//预处理器替换后:(int*)malloc(10 * sizeof(int));
	return 0;
}

        2.宏与函数的命名约定:

        一般来讲,我们使用的宏定义函数,与普通函数的使用语法很相似,这就导致语言本身无法帮我们区分二者。所以我们通常对二者的命名进行约定

①. 宏的名称全部大写。

②. 函数名不要全部大写。

        如此就可以帮助我们区分二者,提升我们程序代码的可读性了。

🍓二、预处理操作符🍓:

        首先我们来看这样的一段代码:

int main()
{
	char* p = "Hellow ""world\n";
    //*p指向两个常量字符串
	printf("Hellow world\n");
	printf("%s", p);

	return 0;
}

        当我们将其编译运行发现,打印结果均为字符串“ Hellow world”

        于是由此我们就可以得知,字符串具有自动连接的特点。那么我们是不是就可以写出下面这样的代码呢?

#define PRINT(FORMAT,VALUE) printf("The value of VALUE is "FORMAT"\n",VALUE);
//可以使用宏来定义函数
//字符串"The value of VALUE is "与"\n"将会自动连接
//构造函数等价于printf("the value of VALUE is %d\n",VALUE);

#include<stdio.h>
int main()
{
	int a = 10;
	PRINT("%d", a + 3);

	return 0;
}

        在这段代码中,我们使用了宏来构造一个新的函数,在这个我们自己构造出来的宏函数中,其中的两个短字符串将会自动连接成为一整个长字符串,并根据我们输入的参数进行打印。于是在这个过程中,就衍生出了两个实用的预处理操作符:# 与 ##

        1.预处理操作符 " # ":

        预处理操作符" # "的作用:将宏参数转变成其对应的字符串

        这是什么意思呢?例如下面这段代码中所使用的 #N

#define _CRT_SECURE_NO_WARNINGS 1
#define PRINT(N) printf("The value of "#N" is %d\n",N);
#N将被视为字符串"N",且字符串 N 在打印时打印的是字符串 N 的内容

#include<stdio.h>
int main()
{
	int a = 10;
	PRINT(a + 3);

	return 0;
}

         在这段代码中,#N 将会被处理为字符串 N ,即" a + 3 ",于是整个宏定义函数就相当于:

printf("The value of ""a + 3"" is %d\n",VALUE);

        即相当于字符串"The value of "字符串"a + 3"字符串" is %d\n"之间进行了自动连接,成为了一整个长字符串

        则最终的输出结果为:

        2.预处理操作符 " ## ":

        预处理操作符" ## "的作用:将位于其两边的符号合成为一个符号

        并且,它允许宏定义从分离的文本片段中创建标识符

        

#define CAT(CLASS,NAME) CLASS##NAME
//宏定义函数的作用为将符号 CLASS 与符号 NAME 合并为符号 CCLASSNAME

#include<stdio.h>
int main()
{
	int class3xiaohong = 888;
	int back = CAT(class3, xiaohong);
	//使用宏定义函数 CAT ,将符号 class3 与符号 xiaohong 合并为 class3xiaohong
	//而符号 class3xiaohong 表示的是值为 888 的 int 类型变量,故用 int 类型变量 back 接收并打印或执行其他操作
	printf("%d\n", back);

	return 0;
}

        在这段代码中,通过宏定义的预处理操作符" ## "将符号" class3 "与符号" xiaohong "进行了合并,合并成了符号" class3xiaohong ",接着我们看到,在这之前我们就已经定义并初始化了 int 类型变量 class3xiaohong,于是我们就可以使用 int 类型的变量对宏定义函数所合成的符号" class3xiaohong "所表示的值进行接收了。

        最后进行打印,验证符号合成结果:

🥝三、条件编译🥝:

        1.简述条件编译指令:

        通过使用条件编译指令,我们在编译一段代码时如果要将一条(或一组)语句编译或舍弃是很方便的。例如一些调试性的代码,删除可惜,保留碍事,于是我们就可以通过使用条件编译指令来实现选择性的进行编译。 

        例如

#include<stdio.h>

int main()
{
	int arr[10] = { 0 };
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		arr[i] = i + 1;
		printf("%02d ", arr[i]);
#if 0
		printf("\n");
#endif
	}

	return 0;
}

        在这段代码中,包含在条件编译指令 #if 与 #endif 之间的换行打印是否执行,就取决于条件编译指令的参数,此时参数为 0 ,即为假,则不进行换行打印

        那么我们再将参数改为1,即真

#include<stdio.h>

int main()
{
	int arr[10] = { 0 };
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		arr[i] = i + 1;
		printf("%02d ", arr[i]);
#if 1
		printf("\n");
#endif
	}

	return 0;
}

        这时条件编译指令参数为真,于是执行其中的代码进行换行打印:

        2.常见条件编译指令:

        ①. 单分支条件编译指令:

#if 常量表达式
    //执行操作
#endif

//或:常量表达式由预编译器求值:
#define __DEBUG__ 1

#if __DEBUG__
    //执行操作
#endif

        ②. 多分枝条件编译指令:

#if 常量表达式
    //执行操作
#elif 常量表达式
    //执行操作
#elif 常量表达式
    //执行操作
...

#endif

        ③. 判断是否被定义:

#if defined(symbol)
    //如果 symbol 被定义过,则执行操作
#endif

//或:
#if !defined(symbol)
    //如果 symbol 没有被定义过,则执行操作
#endif

        ④.嵌套指令:

#if defined(MAX)
    #if 1
        printf("%d\n", a > b ? a : b);
    #endif
#elif define(MIN)
    #if 0
        printf("%d\n", a < b ? a : b);
    #endif
#endif

        通过灵活的嵌套使用条件编译指令,就能实现某条或某组程序代码的选择性编译

🍒总结🍒:

        到这里,我们关于预处理部分的讲解就全部结束了。但是各位小伙伴们可不能就此放松,基础知识的讲解并不意味着我们学习的终结。C 语言是高深而奇妙的,语言学习的道路永无尽头,希望各位小伙伴们能够静下心来多多深入研究,不断发掘C语言的深层逻辑,提升个人的编程能力。同时我们关于 C 语言的进阶之路也就到此为止了。至此我们的 C 语言语法已经全部讲解完毕了,再往后就将进入我们的数据结构与算法部分的学习之中了,各位小伙伴们,期待那时与你们的再次相会,我们随后再会!

        🔥🔥只有承担起旅途风雨,最终才能守得住彩虹满天🔥🔥

        更新不易,辛苦各位小伙伴们动动小手,👍三连走一走💕💕 ~ ~ ~  你们真的对我很重要!最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!

有关【C语言进阶】还说不会?一文带你全面掌握计算机预处理操作的更多相关文章

  1. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  2. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  3. ruby - Highline 询问方法不会使用同一行 - 2

    设置:狂欢ruby1.9.2高线(1.6.13)描述:我已经相当习惯在其他一些项目中使用highline,但已经有几个月没有使用它了。现在,在Ruby1.9.2上全新安装时,它似乎不允许在同一行回答提示。所以以前我会看到类似的东西:require"highline/import"ask"Whatisyourfavoritecolor?"并得到:Whatisyourfavoritecolor?|现在我看到类似的东西:Whatisyourfavoritecolor?|竖线(|)符号是我的终端光标。知道为什么会发生这种变化吗? 最佳答案

  4. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

    我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

  5. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

    几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

  6. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  7. Unity 热更新技术 | (三) Lua语言基本介绍及下载安装 - 2

    ?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------

  8. 7个大一C语言必学的程序 / C语言经典代码大全 - 2

    嗨~大家好,这里是可莉!今天给大家带来的是7个C语言的经典基础代码~那一起往下看下去把【程序一】打印100到200之间的素数#includeintmain(){ inti; for(i=100;i 【程序二】输出乘法口诀表#includeintmain(){inti;for(i=1;i 【程序三】判断1000年---2000年之间的闰年#includeintmain(){intyear;for(year=1000;year 【程序四】给定两个整形变量的值,将两个值的内容进行交换。这里提供两种方法来进行交换,第一种为创建临时变量来进行交换,第二种是不创建临时变量而直接进行交换。1.创建临时变量来

  9. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

    我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

  10. Ruby-vips 图像处理库。有什么好的使用示例吗? - 2

    我对图像处理完全陌生。我对JPEG内部是什么以及它是如何工作一无所知。我想知道,是否可以在某处找到执行以下简单操作的ruby​​代码:打开jpeg文件。遍历每个像素并将其颜色设置为fx绿色。将结果写入另一个文件。我对如何使用ruby​​-vips库实现这一点特别感兴趣https://github.com/ender672/ruby-vips我的目标-学习如何使用ruby​​-vips执行基本的图像处理操作(Gamma校正、亮度、色调……)任何指向比“helloworld”更复杂的工作示例的链接——比如ruby​​-vips的github页面上的链接,我们将不胜感激!如果有ruby​​-

随机推荐