iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C语言如何实现预处理效果
  • 275
分享到

C语言如何实现预处理效果

2023-06-22 07:06:50 275人浏览 薄情痞子
摘要

这篇文章将为大家详细讲解有关C语言如何实现预处理效果,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。前言编译一个C语言程序涉及很多步骤。其中第一个步骤被称为预处理。C语言的预处理器在源代码编译之前对其进行一

这篇文章将为大家详细讲解有关C语言如何实现预处理效果,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

    前言

    编译一个C语言程序涉及很多步骤。其中第一个步骤被称为预处理。C语言的预处理器在源代码编译之前对其进行一些文本性质的操作。它的主要任务包括删除注释、插入被#include指令包含的文件内容、定义和替换由#define指令定义的符号,同时确定代码的部分内容是否应该根据一些条件编译指令进行编译。

    一、预定义符号

    下表为C语言预处理器定义的符号。他们的值有的是字符串常量,有的是十进制数字常量。

    符号示例值含义
    __ FILE__“test.c”当前编译的源文件名
    __ LINE__25本文件当前行号
    __ DATE__“Dec 27 2021”文件被编译日期
    __ TIME__“21:30:23”文件被编译时间
    __ STDC__1如果编译器遵循ANSI C,其值就为1,否则未定义

    二、#define

    我们先来看一下它的用法

    #define name stuff

    有了这条指令以后,每当有符号name出现在这条指令之后时,预处理器就会把它替换为stuff。

    如果定义中的stuff非常长,那就可以将它分成几行,除了最后一行,每行的末尾都要加一个反斜杠,如下面例子所示:

    #define DEBUG_PRINT printf("File %s line %d:" \"x = %d, y = %d, z = %d, \__FILE__, __LINE__, x, y, z)

    这里利用了一个特性:相邻的字符串常量被自动连接为一个字符串。在调试一个存在许多涉及一组变量的不同计算过程的程序时,这种类型的声明非常有用。我们可以很容易的插入一条测试语句,打印出它们的当前值。

    x *= 2;y += x;z = x * y;DEBUG_PRINT;

    1.宏

    #define机制包括一个规定,允许把参数替换到文本中,这种实现通常称为宏(Macro)或者定义宏(define macro)。下面是宏的声明方式:

    #define name(parameter-list) stuff

    其中,parameter-list(参数列表)是一个由逗号分隔的符号列表,它们可能出现在stuff 中。参数列表的左括号必须与name紧邻。否则,参数列表就会被解释为stuf的一部分。

    当宏被调用时,名字后面是一个由逗号分隔的值的列表,每个值都与宏定义中的一个参数相对应。当参数出现在程序中时,与每个参数对应的实际值都将会被替换到stuff中。

    例如:

    #define SQUARE(x) x*xSQUARE(5)

    当这两条语句位于程序中时,预处理器就会用上面的表达式替换下面的表达式,就会变成:5 * 5。

    但是上面这个宏存在一个问题,请大家观察下面的代码:

    a = 5;printf("%d\n", SQUARE(a + 1));

    可能我们直观的觉得这段代码将打印36这个值。但是事实上,它会打印11。Why?来,我们按照宏的规则做一个替换,这条语句将变成:

    printf("%d\n", a + 1 * a + 1);

    发现问题了吗,这里由替换而产生的表达式并没有按照预想的次序进行求值。所以,我们要对宏定义的参数加上括号,包括stuff整体。这样就能产生我们预期的结果了。

    在程序中扩展#define定义符号和宏时,需要涉及几个步骤。

    在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果存在,它们会首先被替换掉。

    替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被它们的值所替代。

    最后,才气对结果文本进行扫描,看看它是否包含了任何由#define定义的符号。如果是的话,就重复上述处理过程。

    2.宏与函数

    宏非常频繁的用于执行简单的计算,比如在两个表达式中寻找其中较大的一个(或较小):

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

    这个功能好像我们也能用函数来实现,那为什么不使用函数呢?有两个原因。首先,用于调用和从函数返回的代码很可能比实际执行这个小型工作的代码更大,所以使用宏要比使用函数在程序中的规模和速度都更胜一筹。

    其次,更为重要的是,函数的参数必须声明为一种特定的类型,所以它只能在类型合适的表达式中使用。但是宏是与类型无关的。

    有优点就会有缺点,和使用函数相比,使用宏的不利之处在于每次使用宏时,一份宏定义代码的副本都将会插入到程序中。除非宏非常短,否则使用宏可能会大幅度增加程序的长度。

    还有一些任务无法用函数来实现,比如下面这个代码:

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

    type是一个数据类型,而函数是无法将类型作为参数传递的。

    3.带副作用的宏参数

    当宏参数在宏定义中出现的次数吵过一次时,如果这个参数具有副作用,那么在使用这个宏时就可能出现危险,导致不可预料的后果。副作用就是在表达式求值时出现永久性的后果。如下:

    x + 1;

    这个表达式无论执行几百次都是一样的,所以它没有副作用。

    x++;

    但是这个表达式就不同了,每次执行都会改变x的值,每一次执行都是一个不同的结果。所以,这个表达式是具有副作用的。我们看下面的例子,你觉得它会打印出什么:

    #define MAX(a, b) ((a) > (b) ? (a) : (b))x = 5;y = 8;z = MAX(x++, y++);printf("x =%d, y = %d, z = %d\n", x, y, z);

    其结果是: x = 6, y = 10, z = 9。产生这个结果的原因是那个较小的值只增加了一次,而那个较大的值却增加了两次——第一次是在比较的时候,第二次是在执行?后面的表达式时。这就是一个具有副作用的宏参数,我们在使用的时候一定要注意。

    4. 宏和函数的不同

    通过一个表格来分析:

    属性#define宏函数
    代码长度每次使用时,宏代码都被插入到程序中。除了非常小的宏,程序的长度将大幅增长函数代码只出现在一个地方,每次使用函数时,都调用那个地方的同一份代码
    执行速度更快存在函数调用和返回的额外开销
    操作符优先级宏参数的求值是在所有周围表达式的上下文环境里,除非它们加上括号,否则临近操作符的优先级可能会发生改变函数参数指在函数调用时求值一次,其结果传递给函数,求值结果更容易预测
    参数求值参数每次用于宏定义时,它们都将重新求值。由于多次求值,具有副作用的参数可能会产生不可预料的后果参数在函数被调用前只求值一次,在函数中多次使用参数并不会导致多个求职过程。参数的副作用并不会造成任何特殊的问题
    参数类型宏与类型无关。只要对参数的操作是合法的,它可以使用任何类型的参数函数的参数是与类型有关的,如果参数的类型不同,就需要使用不同的函数,即使它们执行的任务是相同的

    5.#undef

    #undef这个预处理指令用于移除一个宏定义:

    #undef name

    如果现存的名字需要被重新定义,那么首先必须用#undef移除它的旧定义。

    三、条件编译

    在编译一个程序时,如果可以翻译或忽略选定的某条语句或某组语句,会给我们带来极大的便利。而条件编译(conditional compilation)可以实现这个目的。使用条件编译,可以选择代码的一部分是被正常编译还是完全忽略。用于支持条件编译的基本结构是#if指令和#endif指令。一下是其使用方式:

    #if constant-expressionstatements#endif
    #if constant-expressionstatements#elif constant-expressionother statements#elseother statements#endif

    同时,条件编译的另一个用途是在编译时选择不同的代码部分。所以#if指令还具有可选的#elif和#else子句。如下:

    #if constant-expressionstatements#elif constant-expressionother statements#elseother statements#endif

    #elif子句出现的次数可以不限。但是每个常量表达式(constant-expression)只有当前面所有常量表达式的值都为假时才会被编译。#else子句中的语句只有当前面所有常量表达式的值都为假时才会被编译。

    四、文件包含

    #include指令使另一个文件的内容被编译,就好像它实际出现在#include指令出现的位置一样。这种替换执行的方式很简单:预处理器删除这条指令,并用包含文件的内容取而代之。如果一个头文件被包含到十个源文件中,那它实际上被编译了十次。

    1.函数库文件包含

    C语言编译器支持两种不同类型的#include文件包含:函数库文件和本地文件。事实上,他们之间的区别很小。

    函数库文件的包含使用以下语法:

    #include<filename>

    对于filename(文件名),并没有任何的限制,不过根据规定,标准库文件以一个.h后缀结尾。

    编译器通过观察由编译器定义的“一系列标准位置”查找函数库头文件。你所使用的编译器文档会说明这些标准的位置是什么,以及怎样修改它们或者在列表中添加其他位置。

    2.本地文件包含

    以下是#include指令的另外一种形式:

    #include"filename"

    标准允许编译器自行决定是否把本地形式的#include和函数库形式的#include区别对待。可以先对本地头文件使用一种特殊的处理方式,如果失败,编译器再按照函数库头文件的处理方式对待它们进行处理。

    处理本地头文件的一种常见策略就是在源文件所在的当前目录进行查找,如果该头文件并未找到,编译器就像查找函数库头文件一样在标准位置查找本地头文件。

    关于“C语言如何实现预处理效果”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

    --结束END--

    本文标题: C语言如何实现预处理效果

    本文链接: https://www.lsjlt.com/news/303085.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • C语言如何实现预处理效果
      这篇文章将为大家详细讲解有关C语言如何实现预处理效果,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。前言编译一个C语言程序涉及很多步骤。其中第一个步骤被称为预处理。C语言的预处理器在源代码编译之前对其进行一...
      99+
      2023-06-22
    • 详解C语言的预处理效果
      目录前言一、预定义符号二、#define1.宏2.宏与函数3.带副作用的宏参数4. 宏和函数的不同5.#undef三、条件编译四、文件包含1.函数库文件包含2.本地文件包含总结前言 ...
      99+
      2024-04-02
    • C语言如何实现流星雨效果
      小编给大家分享一下C语言如何实现流星雨效果,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!上次忘记说了,因为我们是用C语言写的所以是控制台程序,创造不出来界面,那怎...
      99+
      2023-06-25
    • C语言预编译#define(预处理)
      目录一、预定义符号二、#define 定义标识符三、#define 定义宏四、#define 替换规则:五、#和## 两个符号(少见)六、宏和函数的对比七、#undef一、预定义符号...
      99+
      2024-04-02
    • C语言预处理详解
      目录一,预定义符号二,#define1,#define 定义标识符2,#define 定义宏3,#define 替换规则三,##的作用1,概念2,带副作用的宏参数3,宏和函数对比四,...
      99+
      2024-04-02
    • 如何实现C++语言中的毛玻璃效果
      今天就跟大家聊聊有关如何实现C++语言中的毛玻璃效果,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。在基于Windows Vista的普通Windows应用程序及对话框程序中,如何利用...
      99+
      2023-06-17
    • C语言实现代码雨效果
      本文实例为大家分享了C语言实现代码雨效果的具体代码,供大家参考,具体内容如下 一、项目描述和最终的效果展示 项目:   让字符从上到下依次的下落,呈现出代码雨。 最终效果图...
      99+
      2024-04-02
    • C语言如何实现酒店预订管理系统
      这篇“C语言如何实现酒店预订管理系统”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“C语言如何实现酒店预订管理系统”文章吧。课...
      99+
      2023-06-30
    • C语言的预处理介绍
      目录前言一、预定义符号二、#define1.宏2.宏与函数3.带副作用的宏参数4.宏和函数的不同5.#undef三、条件编译四、文件包含总结前言 编译一个C语言程序涉及很多步骤。其中...
      99+
      2024-04-02
    • 如何在R语言中实现数据预处理操作
      如何在R语言中实现数据预处理操作?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。一、项目环境开发工具:RStudioR:3.5.2相关包:infotheo,dis...
      99+
      2023-06-15
    • 详解C语言之预处理(上)
      目录程序的翻译环境编译预编译:编译:汇编:链接合并段表:#define的用法1.#define定义标识符,例如2.#define定义宏  3.#define实现将...
      99+
      2024-04-02
    • 详解C语言之预处理(下)
      目录#define定义宏带副作用的宏参数#define定义宏的优点#define定义宏劣势预处理预定义符号预处理指令条件编译1.调试性代码2.防止重复的头文件多次编译总结#defin...
      99+
      2024-04-02
    • C语言中#define预处理语法总结
      目录一、使用#define定义标识符常量语法1:语法2:二、#define来定义带有参数的宏三、C语言给我们定义好的一些标识符常量一、使用#define定义标识符常量 语法1: ...
      99+
      2024-04-02
    • C语言实现流星雨效果流程
      目录一、头文件二、结构体三、初始化四、绘制函数五、移动函数六、界面设计七、主函数总结视频讲解感谢序 再亮眼的流星,也会一闪而过。 嗨!这里是狐狸~~ 没错,我又来了,上次的“烟花”表...
      99+
      2024-04-02
    • 如何用Go语言实现高效的自然语言处理算法?
      自然语言处理(NLP)是人工智能领域中的一个热门话题,它主要涉及人类语言的处理和理解。而Go语言则是近年来备受推崇的编程语言之一,它的并发性和高效性使得它成为了一种非常适合用于NLP领域的语言。在本文中,我们将介绍如何用Go语言实现高效的自...
      99+
      2023-09-08
      响应 自然语言处理 leetcode
    • C语言实现酒店预订管理系统
      本文实例为大家分享了C语言实现酒店预订管理系统的具体代码,供大家参考,具体内容如下 课设要求: 客房信息管理。 客人预订及入住信息管理。 各种查询和统计功能。 本系统要有通用性、界面...
      99+
      2024-04-02
    • C语言中预处理有什么用
      这篇文章主要介绍了C语言中预处理有什么用,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。程序的翻译环境源文件被转换成可执行的机器指令时所处的环境称为翻译环境。由源文件(.c)转...
      99+
      2023-06-25
    • CSS3如何实现预载动画效果
      小编给大家分享一下CSS3如何实现预载动画效果,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!实现如图所示的动画效果:预载动画一:...
      99+
      2024-04-02
    • C语言进阶教程之预处理
      目录一.代码运行是的两种环境二.翻译环境三.预定义符号四.#define1.define  定义宏2.带有副作用的宏参数五.#define定义宏 与函数对比六.预处理指令七...
      99+
      2023-02-10
      什么是预处理 c语言编译预处理命令 c语言预处理指令作用
    • 批处理如何实现循环效果
      这篇文章主要介绍批处理如何实现循环效果,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!第一次运行 执行命令工A 第二次运行 执行命令工B 第三次运行 执行命令工A ...............
      99+
      2023-06-09
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作