【C语言更新】熟练使用#define宏定义,中文编程不是梦

文/Edward


前面我们在讲解程序编译的时候,编译器做的第一步就是预处理。C语言的预处理,其实是编译器在对整个工程编译之前做的一些文本性质的工作,例如我们经常使用的#include,这就是一个典型的文件包含预处理,当启动编译的时候,编译器首先先做预处理,即将#include后面包含的那个文件里面的内容,全部复制到当前的.c文件中来,接着,再进行C语言源文件的编译。除了文件包含之外,C语言中的预处理还有很多,而这些预处理对于我们编程来说,都可以帮助我们提高代码的易读性和代码质量。


#define

#define预处理的作用,一般在一些书上面仅仅称其为“宏定义”,其实这个称呼是不严谨的,一个#define预处理其实包含两种意思,第一种意思是“宏定义”,第二个层面的意思是替换,下面的内容,我们将会以上面两层意思分开讲解。

  #define替换

也许我们在单片机编程中,绝大多数用户使用的仅仅只是#define预处理的替换功能,#define的替换格式为:

#define NAME 需要替换的内容

比如,我们一般常用的用来定义圆周率Π,就可以写成:

#define PI 3.1415926

那么以后的程序代码里面只要出现PI这个标号,编译器都将直接将其替换成一个浮点数3.1415926。

在用#define定义标号的时候需要注意,一般地我们都以大写字母来拼写这个标号,而且这个标号在用#define定义时,我们都默认地将其放入相应的.h头文件中。如图1所示的求圆形面积和周长的程序。

图1 求圆的周长和面积

用#define定义的标号不止可以替换一些数值,还可以替换关键词和函数,例如,想要让C语言变成一个中文的编程语言,就可以直接用#define定义中文标号来替换C语言的关键词,如图2所示。

图2 用中文编写C语言

需要注意的是,MinGW编译器自身不支持中文类型的变量,所以如果要尝试只能在Visualstudio软件中使用MSVC来尝试。

#define除了可以替换数值、关键词和函数之外,还可以用来替换程序语句,我们可以将需要执行的程序语句,利用#define重新定义成一个标号,如图3所示。

图3 #define替换程序语句

在图3中,我们利用#define定义了一个程序计算语句,这个标号在程序执行的时候就会自动被替换成后面的2*3运算语句去执行了。接着我们再来看一段代码。如8-1-4所示。

图4 错误的#define替换

按照我们正常的理解,图4中的程序理论上来说应该输出25才对,但是为什么结果却和我们想象的不一样呢?这是因为#define定义的标号在编译的时候是文本直接替换的,因此当在程序里面执行STENCE*STENCE的时候,我们认为的应该执行(2+3)*(2+3),而实际上STENCE是直接被2+3替换的,所以在程序编译时的真实替换应该是2+3*2+3,因此输出的值才和我们想象中的不一样,这就是典型的#define替换错误。只需要在2+3外面加上括号即可,如图5所示。

图5 正确的#define程序语句替换

而当我们在替换多条语句的时候,一定要用“do{……}while(0);“的形式来将标号里面的多条执行语句打包好,以防止不必要的错误产生。如图6所示。

图6# define替换多条程序语句

 

#define除了用作简单和复杂的程序文本替换之外,这个机制还包括了一个规定,即可以将参数替换到文本中去进行计算,这种实现通常被称为宏(macro)。

宏定义的声明方式为:

#define 宏名称(参数1,参数2,……)  带参数的表达式

当宏被调用时,参数列表中的每一个值都会与宏表达式实体中的每一个值所一一对应,并且进行替换。如,我们定义一个用于计算平方的宏,就可以写成:

#define SQUARE(x) x*x

下面程序使用宏定义计算5的平方,就可以直接使用SQUARE(5)。

如图7所示,我们可以将圆的面积和周长计算分别写成宏的形式进行运算。

图7 宏定义计算圆的周长和面积

但是还需要注意的是,宏定义的参数替换也仅仅是文本形式的替换,如图8所示。

图8 宏定义的错误计算

图8的程序中,我们原本想的是,输入的半径变成11之后,通过调用宏,并且传入参数rad+ 1,理论上来说应该和8-1-7中输出一样的计算结果才对,但是实际上,这个传入的参数在替换时也是仅仅被当作文本去替换了,因此图8程序实际的计算过程应该是,以周长为例,2*3.1415926*11+1=70.12。所以在宏定义的时候,我们也应该为其参数增加括号,以提高整个宏的完整性。如图9所示。

图9 宏定义参数的正常使用

除了上述的功能之外,宏定义最常被使用的就是比较两个数的大小了,之前我们比较两个数的大小都是使用if来判断的,但是学了宏之后,结合三目运算符就可以直接使用一个宏定义来完成了,如图10所示。

图10 使用宏定义比较大小


本章历程代码已经上传Git,仓库地址:https://gitee.com/huangqilong119/joy-create-clanguage-code.git


(0)

相关推荐

  • 实现一个VB程序的全过程!精心总结!

    I Love VB 今天,我们结合一个具体的VB程序,来讲解一下如何按照既定要求完成一个VB程序. 首先,今天讲解的程序要实现的功能是: 在文本框中输入半径,然后点击求直径.周长.面积单选按钮,则可以 ...

  • 一些值得被定义为常用C语言头文件库的漂亮宏定义(值得收藏,以备使用参考)

    写好C语言,漂亮的宏定义很重要,使用宏定义可以防止出错,提高可移植性,可读性,方便性等等.下面列举一些成熟软件中常用的宏定义. 1. 防止一个头文件被重复包含 1#ifndef COMDEF_H 2# ...

  • 【C语言更新】结构体的定义及使用

    文/Edward 首先先思考一个问题,假设某一天你去了一家策划公司,接到了一个策划需求,比如为新上市的某款手机写一个市场推广的文案,并且在电脑上面打印出来.那么在写这个文案的时候,你肯定是会需要着重地 ...

  • C语言零基础教程之预处理和宏定义篇

    https://m.toutiao.com/is/JTpvb14/ 前言 上一章节主要讲解C语言文件操作,本章节主要讲解C语言预处理和宏定义. C语言预处理 在C语言中,预处理指令是在实际源代码编译之 ...

  • link script(链接器ld吃的文件)中使用宏定义的解决方案

    问题:工作中遇到一个需求:需要在ld script中使用类似C语言的define等宏定义来做一些判断和替换 实验: 1:理论上*.c中都能用,是否gcc/ld也支持在ld script中直接用宏呢,结 ...

  • 【C语言更新】条件编译

    文/Edward 有时候我们在做项目的时候,一个全新的项目代码并不会全部重新写,这个新项目往往只是某一个主线项目的分支,因此可以借鉴之前的代码,然后对需要修改的地方进行修改.但是,如果这两份代码改动的 ...

  • 【C语言更新】结构体中实现函数成员以及回调函数

    文/Edward 前面说,结构体内部的成员变量可以是普通变量,数组,除了这些变量之外,还可以是指针,结构体,枚举,共用体等.综上所述的结构体内部成员中,我们可以发现一个结构体内部的成员竟然不包含函数. ...

  • 【C语言更新】指向函数的指针

    文/Edward   定义一个指向函数的指针 前面我们说了,指针的本质其实就是用来存放地址的变量,将一个对象的地址赋值给指针的过程被称为指向.我们前面已经讲过了指针指向变量,指针指向数组,指针指向字符 ...

  • 【C语言更新】指针函数

    文/Edward 今天开始,我们将来介绍C语言里面最让人头痛的两个东西,指针函数和指向函数的指针. 指针函数这个名字乍一看非常唬人,又是指针又是函数的,但是其实它并没有想象的那么复杂,千万别被它的名字 ...

  • 【C语言更新】C语言中字符串的操作

    文/Edward 在C语言的实际使用中,很多时候会去使用指针传递一些字符串,而C语言中也有很多关于字符串处理的库函数给大家来使用,只要在使用的时候包含头文件"string.h"就可 ...