首页 > 其他分享 >C语言关于预处理的基础介绍

C语言关于预处理的基础介绍

时间:2024-06-06 20:02:15浏览次数:19  
标签:__ 定义 ++ MAX 介绍 C语言 参数 替换 预处理

一:预定义符号

        在c语言中有一些预定义的符号,这些符号已经定义好了,用户不需要再次定义只需要使用即可。

  1.  __FILE__ :显示当前进行编译的源文件
  2. __LINE__:显示当前代码行号
  3. __DATE__:显示当前文件被编译的日期
  4. __TMIE__:显示当前文件被编译的时间
  5. __STDC__:查看当前编译器是否遵循ANI C。如果返回值为1,反之结构未定义

        

        由此可见vs编辑器是不遵循ANI C标准的。

二:#define

        1.#define定义标识符:

        

从上示例可以看出,#define不仅可以定义符号常量,还可以定义字符串量。

        2.#define定义宏

                #define机制包括了一个定义,它允许把参数替换到文本中,这种实现方法成为定义宏。

                

这里需要注意 ADD后面的左括号需要紧跟着ADD,如果两者之间有空格那么都会解释成ADD宏的一部分。

        

          我们观察上图例子,可以看到MUL1与MUL2中的表达式一样只是区别在于,一个有加()一个没有,但输入相同参数的时,产生的结果确实两个不同的值。原因在于宏在使用时候会将参数直接替换,而上图示例宏将参数替换后变成两个不同的表达式,后根据符号优先级产生了不同的结果。   使用请注意:在写宏时请不要吝啬括号。

        3.#define的替换规则

                1.简单的文本替换#define 指令可以将标识符替换为指定的文本。

                2.带参数的宏: 宏也可以带有参数,类似于函数,在替换时,宏的名字会被他们的参数替换。

                3.宏定义的范围: 宏定义的作用范围从定义点开始一直到文件末尾,除非被undef指令取消。

                4.宏应避免递归

三:#与##

        1.#:

                首先来看下面一段代码

                

        可以看到在第二个printf语句中有两个字符串,而打印时会合并成一个字符串。

                        

        

        可以看到a和b的输出是相似的,此时可以想到是不是可以用函数来进行简化。但肯定的是函数是做不到这样的,因为函数只能改变其值,但不能改变文本如 of a 与 of b,函数做不到这样的替换,此时就可以就可以用到宏。

                

        上示例 定义了一个宏 将刚才printf语句变成宏的参数,将printf语句拆分成两个字符串,而在两个字符串中间 是#N,那么#的作用是:将#后的参数变成字符串。将原本的a的参数10替换成变量名a。那么下次在想输出类似的语句只需要调用宏传入参数即可。

       

        2.##:

                ##可以将位于它两边的标识符合成为一个标识符。

        

        观察上图,这定义了一个宏CAT,参数为(Class,num),其值为Class##num。意思是将Class与num连接,组成Classnum参数。 此时在main函数里定义int类型的变量Classnum,接着打印宏,将参数Class与num带入宏,就会组成刚才定义的Classnum的变量。如果此时将main函数里定义的Classnum参数注释掉或者改变成别的参数,那么结果是未定义的。

        



四:带副作用的宏参数

        如果宏参数在宏定义中出现超过一次的时候,如果此时宏参数带有副作用,那么在使用这个宏时可能会出现意想不到的危险,会与预想的结果出现严重偏差。

        例如: x+1 不带副作用(不会改变其x值) , x++带副作用 (会改变其x值)。     

            

        从上图可以看到,在宏定义中使用了三元运算符表达式。接着在main() 函数中,定义了两个整型变量 a 和 b,分别初始化为 5 和 4。然后调用了 MAX(a++, b++)。                   这会被展开成((5++)>(4++))?  在这个表达式中,(5++) 和 (4++) 会被进行比较,比较完再经行后置++操作,这里5与4先进行比较,接着5++变成了6,4++变成了5,而因为5>4,返回的是第二个表达式(a),而a这里会被替换成(6++)因为刚才5已经变成6了。又因为是后置++,先将数值6返回给ret,最后6++变成7。所以a=7,b=5(因为第三个表达式并没有执行),ret=6 。

      宏的缺点:        

  1.  宏是无法进行调试的,宏展开是在预处理阶段完成的,因此在编译器看到代码之前,它们已经被替换为具体的代码。
  2. 每一次使用宏时,一份宏定义的代码都会插入到程序中,除非宏比较短,否则可能会增加代码长度。
  3. 宏因为与类型无关,所以宏不够严谨。
  4. 使用宏的代码可能难以理解和维护,因为宏展开后的代码可能与原始代码有很大差异,而且不容易阅读。
  5. 宏是不安全的。由于宏是简单的文本替换,没有类型检查或作用域限制,因此可能会导致意想不到的行为。例如,如果在宏中使用了传递给它的表达式多次求值,就会导致副作用,如上面例子中的 a++ 和 b++ 被多次执行。

        

      移除宏:#undef

         #undef用来移除宏命令。

                

五:条件编译

        条件编译是一种编程技术,通常用于根据预定义的条件来控制程序的编译过程。条件编译通过预处理器指令来实现,比如#ifdef、#ifndef等指令。通过在源代码中使用这些指令,可以根据预定义的宏或条件来选择性地排除或添加代码块。

                        

       

关于判断宏是否被定义的指令:

                1.#if defined(宏)  || #ifdef 宏

                2.#if !defined(宏) || #ifndef 宏   

                  #if defined(MAX):定义了MAX就打印

                #if !defined(MAX):没有定义MAX就打印

                #ifdef MAX:定义了MAX就打印

                #ifndef:没有定义MAX就打印

六:头文件包含

        文件包含是通过预处理器指令 #include来实现的。#include 指令告诉编译器在编译时将指定的文件内容包含到当前文件中。这种机制使得可以将一些通用的代码放在单独的文件中,然后通过 #include 指令将其包含到需要使用的程序中。

            从上图示例可以看出 我的test.c的文件只有#include"head.h"的文件包含,编译器会在源文件下的目录进行查找头文件,如果该文件未找到,编译器就会像查找库函数头文件一样在标准位置下查找头文件。如果找不到就会发生编译错误提示。文件还可以进行嵌套包含,上图例子就是在head.h的文件中包含着库文件。

       

        关于< >与" "的区别:

            < >与" "的查找策略不同。

               #include<stdion.h> :查找策略为直接去库目录下查找。

              #include"head.h":查找策略为先去代码所在的路径下查找,如果找不到再去库目录下找。

        

标签:__,定义,++,MAX,介绍,C语言,参数,替换,预处理
From: https://blog.csdn.net/2301_80894970/article/details/139480370

相关文章

  • Qt中图表图形绘制类介绍
    接上篇介绍QChart相关的类,本片主要在QChart载体上进行图表图形绘制使用各种形状的图类。一.QXYSeries类QXYSeries类是QLineSeries折线图,QSplineSeries样条曲线图,QScatterSeries散点图的基类;QXYSeries类的使用都可以参考下面详细介绍的折线图,样条曲线图,散点图等的应用。......
  • CUDA程序优化-1.基础介绍
    简介本合集主要介绍我在开发分布式异构训练框架时的CUDA编程实践和性能优化的相关内容。主要包含以下几个部分:介绍CUDA的基本概念和架构,帮助读者建立对CUDA的初步认识,包括硬件架构/CUDA基础等内容介绍一些性能优化技巧和工具,帮助读者优化CUDA程序的执行效率结合具体的代码示......
  • C语言:详解gcc驱动程序完成编译、汇编、链接的过程
    相关阅读C语言https://blog.csdn.net/weixin_45791458/category_12423166.html?spm=1001.2014.3001.5482    gcc是一个命令,严格意义上说,它只是一个驱动程序,而不是一个编译器。gcc负责调用GNU工具链中的预处理器、编译器、汇编器、链接器等工具,通过传递不同的选项给g......
  • 【C语言】指针(4)
    一、回顾 在这之前,我们学习了很多关于指针的内容,我们先在这里简单的回顾一下。1、一级指针int*p;  --整形指针-指向整形的指针 char*p;...void*p;......2、二级指针int**p; char**p;...3、数组指针--指向数组的指针int(*p)[];intmain(){......
  • nginx mirror流量镜像详细介绍以及实战示例
    nginxmirror流量镜像详细介绍以及实战示例1.nginxmirror作用2.nginx安装3.修改配置3.1.nginx.conf3.2.conf.d目录下添加default.conf配置文件3.3.nginx配置注意事项3.3.nginx重启4.测试1.nginxmirror作用为了便于排查问题,可能希望线上的请求能够同步到测试环境,以......
  • C语言杂谈:函数栈帧,函数调用时到底发生了什么
            我们都知道在调用函数时,要为函数在栈上开辟空间,函数后续内容都会在栈帧空间中保存,如非静态局部变量,返回值等。这段空间就叫栈帧。    当函数调用,就会开辟栈帧空间,函数返回时,栈帧空间就会被释放。这里的释放并非清空,而是让其无效化,可以后续的使用。1,......
  • 网络安全行业介绍
    网络安全行业介绍一、行业概述网络安全行业是一个跨学科的综合性领域,涵盖了计算机科学、网络技术、通信技术、密码技术和信息安全技术等多个方面。其核心目标是保护网络系统的硬件、软件及其中存储、传输的数据免受任何形式的未授权访问、损坏、攻击或滥用,确保网络环境的可用性......
  • osgearth2.10 demo功能介绍 转载文章
    osgearth-2.10demo:说明:1、运行环境win7x64旗舰版,CPUi5-64008核,8G内存;2、括号内是对应demo的测试参数(.earth);3、配置OSG_FILE_PATH;4、参数命令行可以查看各个demo需要的输入参数;5、前缀说明:gui界面程序、cmd控制台程序、non功能未知;6、程序后括号里的non表示不需要通过命令......
  • 001__C语言程序入门
    一、第一个程序:helloworld配置部署好vsCode之后,就可以直接在上面写代码了,新建一个新的C程序文件,向屏幕输出一串字符“HelloWorld!”下面,从整体上来分析一下这个最简单的C语言程序,将这个最简程序的各个部分剖析清楚,明白我们写下的每一个字符的具体含义。二、C语言的基本结......
  • 【Python机器学习】无监督学习——不同类型的预处理
    之前学习过,一些算法(比如神经网络和SVM)对数据缩放非常敏感。因此,通常的做法是对特征进行调节,使数据更适合于这些算法。通常来说,这是对数据的一种简单的按照特征的缩放和移动。举例:importmglearn.plotsimportmatplotlib.pyplotaspltmglearn.plots.plot_scaling()plt.sh......