学习c语言:预处理详解(宏定义)

news2024/11/15 17:21:21

1.预定义符号

C语⾔设置了⼀些预定义符号,可以直接使⽤,预定义符号也是在预处理期间处理的。

__FILE__ //进⾏编译的源⽂件
__LINE__ //⽂件当前的⾏号
__DATE__ //⽂件被编译的⽇期
__TIME__ //⽂件被编译的时间
__STDC__ //如果编译器遵循ANSI C,其值为1,否则未定义

 举个例⼦:

printf("file:%s line:%d\n", __FILE__, __LINE__); 

 2. #define定义常量

基本语法:

#define name stuff 

 举个例⼦:

#define MAX 1000
#define reg register //为 register这个关键字,创建⼀个简短的名字
#define do_forever for(;;) //⽤更形象的符号来替换⼀种实现
#define CASE break;case //在写case语句的时候⾃动把 break写上。
// 如果定义的 stuff过⻓,可以分成⼏⾏写,除了最后⼀⾏外,每⾏的后⾯都加⼀个反斜杠(续⾏符)。
#define DEBUG_PRINT printf("file:%s\tline:%d\t \
date:%s\ttime:%s\n" ,\
__FILE__,__LINE__ , \
__DATE__,__TIME__ )

 思考:在define定义标识符的时候,要不要在最后加上 ; ?

⽐如:

#define MAX 1000;
#define MAX 1000

 建议不要加上 ; ,这样容易导致问题。
⽐如下⾯的场景:

if(condition)
max = MAX;
else
max = 0;

 如果是加了分号的情况,等替换后,if和else之间就是2条语句,⽽没有⼤括号的时候,if后边只能有⼀条语句。这⾥会出现语法错误。

3. #define定义宏

#define?机制包括了⼀个规定,允许把参数替换到⽂本中,这种实现通常称为宏(macro)或定义宏(definemacro)。
下⾯是宏的申明⽅式:

#define name( parament-list ) stuff 

其中的 parament-list 是⼀个由逗号隔开的符号表,它们可能出现在stuff中。

 注意:
参数列表的左括号必须与name紧邻,如果两者之间有任何空⽩存在,参数列表就会被解释为stuff的⼀部分。
举例:

#define SQUARE( x ) x * x 

 这个宏接收⼀个参数 x .如果在上述声明之后,你把 SQUARE( 5 ); 置于程序中,预处理器就会⽤
下⾯这个表达式替换上⾯的表达式: 5 * 5

警告:
这个宏存在⼀个问题:
观察下⾯的代码段:

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

乍⼀看,你可能觉得这段代码将打印36,事实上它将打印11,为什么呢??
替换⽂本时,参数x被替换成a+1,所以这条语句实际上变成了: 

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

 这样就⽐较清晰了,由替换产⽣的表达式并没有按照预想的次序进⾏求值。

在宏定义上加上两个括号,这个问题便轻松的解决了:
#define SQUARE(x) (x) * (x) 

 这样预处理之后就产⽣了预期的效果:
printf ("%d\n",(a + 1) * (a + 1) ); 

这⾥还有⼀个宏定义:
#define DOUBLE(x) (x) + (x) 

定义中我们使⽤了括号,想避免之前的问题,但是这个宏可能会出现新的错误。
int a = 5;
printf("%d\n" ,10 * DOUBLE(a));

这将打印什么值呢?看上去,好像打印100,但事实上打印的是55.?
我们发现替换之后:

printf ("%d\n",10 * (5) + (5)); 

 乘法运算先于宏定义的加法,所以出现了 55 .
这个问题,的解决办法是在宏定义表达式两边加上⼀对括号就可以了。

#define DOUBLE( x) ( ( x ) + ( x ) ) 

 提⽰:
所以⽤于对数值表达式进⾏求值的宏定义都应该⽤这种⽅式加上括号,避免在使⽤宏时由于参数中的操作符或邻近操作符之间不可预料的相互作⽤。

4. 带有副作⽤的宏参数

当宏参数在宏的定义中出现超过⼀次的时候,如果参数带有副作⽤,那么你在使⽤这个宏的时候就可能出现危险,导致不可预测的后果。副作⽤就是表达式求值的时候出现的永久性效果。

例如:
x+1; //不带副作⽤
x++; //带有副作⽤

 MAX宏可以证明具有副作⽤的参数所引起的问题。
#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); //输出的结果是什么?

 这⾥我们得知道预处理器处理之后的结果是什么:

z = ( (x++) > (y++) ? (x++) : (y++)); 
所以输出的结果是:x=6 y=10 z=9

5. 宏替换的规则

在程序中扩展#define定义符号和宏时,需要涉及⼏个步骤。
1. 在调⽤宏时,⾸先对参数进⾏检查,看看是否包含任何由#define定义的符号。如果是,它们⾸先被替换。
2. 替换⽂本随后被插⼊到程序中原来⽂本的位置。对于宏,参数名被他们的值所替换。
3. 最后,再次对结果⽂件进⾏扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。
注意:
1. 宏参数和#define定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。
2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。

6. 宏函数的对⽐

宏通常被应⽤于执⾏简单的运算。
⽐如在两个数中找出较⼤的⼀个时,写成下⾯的宏,更有优势⼀些

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

 那为什么不⽤函数来完成这个任务?
原因有⼆:
1. ⽤于调⽤函数和从函数返回的代码可能⽐实际执⾏这个⼩型计算⼯作所需要的时间更多。所以宏⽐函数在程序的规模和速度⽅⾯更胜⼀筹。
2. 更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使⽤。反之这个宏怎可以适⽤于整形、⻓整型、浮点型等可以⽤于 > 来⽐较的类型。宏是类型⽆关的。
和函数相⽐宏的劣势:
1. 每次使⽤宏的时候,⼀份宏定义的代码将插⼊到程序中。除⾮宏⽐较短,否则可能⼤幅度增加程序的⻓度。
2. 宏是没法调试的。
3. 宏由于类型⽆关,也就不够严谨。
4. 宏可能会带来运算符优先级的问题,导致程容易出现错。
宏有时候可以做函数做不到的事情。⽐如:宏的参数可以出现类型,但是函数做不到。

#define MALLOC(num, type)\
(type )malloc(num sizeof(type))
...
//使⽤
MALLOC(10, int); //类型作为参数
//预处理器替换之后:
(int )malloc(10 sizeof(int));

 以上是宏定义部分的预处理操作,剩余的操作下集再来。感谢观看!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1500094.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker镜像及Dockerfile详解

1 Docker镜像用途 统一应用发布的标准格式支撑一个Docker容器的运行 2 Docker镜像的创建方法 基于已有镜像创建基于本地模板创建基于Dockerfile创建 (实际环境中用的最多) 2.1 基于已有镜像的创建 将容器里面运行的程序及运行环境打包生成新的镜像 …

盘点美貌与个性兼备的国漫女神,她们绝不是花瓶!

在近年来的影视作品里,女性角色不再只是简单的陪衬或是花瓶,她们以各具特色的形象,展现了独立、坚韧和多元的女性力量。而在二次元的世界里,众多女角色同样散发着耀眼的光芒。正值国际妇女节,一起来看看国漫中那些兼具…

新能源车高压线束更换VR虚拟互动教学保障了培训安全可控

随着新能源汽车市场的快速发展,对于新能源汽车检修人才的需求也日益增长。然而,传统的培训模式往往存在一些限制,如培训周期长、成本高、实践机会少等。为了解决这些问题,新能源车检修VR互动培训应运而生,成为一种创新…

分享MDN前端结构化技能、实践指南、学习资源

前言 MDN课程为成为一名成功的前端开发人员提供了一个结构化的基本技能和实践指南,以及推荐的学习资源。 先看下让人不得不服的书《宝宝的网页设计》(套装共3册) 宝宝的HTML、宝宝的CSS、宝宝的JavaScript 全球首套中英文宝宝编程启蒙书&a…

文献学习-14-一种用于高精度微创手术的纤维机器人

Authors: Mohamed E. M. K. Abdelaziz1,2 †, Jinshi Zhao1,3 †, Bruno Gil Rosa1,2 , Hyun-Taek Lee4 , Daniel Simon3,5 , Khushi Vyas1,2 , Bing Li6,7 , Hanifa Koguna3 , Yue Li1 , Ali Anil Demircali3 , Huseyin Uvet8 , Gulsum Gencoglan9,10, Arzu Akcay11,12, Moham…

WinCE USB驱动架构及术语明析

一、层式驱动的概念。 WinCE驱动多为层式驱动,分为MDD和PDD两层。 MDD包含通用的驱动代码,向操作系统提供了驱动接口,该层代码调用PDD功能访问硬件。 PDD部分包含与硬件平台相关的特殊代码,不具有通用性。 之所以要分层&#xff0…

050-WEB攻防-PHP应用文件包含LFIRFI伪协议编码算法无文件利用黑白盒

050-WEB攻防-PHP应用&文件包含&LFI&RFI&伪协议编码算法&无文件利用&黑白盒 #知识点: 1、文件包含-原理&分类&危害-LFI&RFI 2、文件包含-利用-黑白盒&无文件&伪协议 演示案例: ➢文件包含-原理&分类&am…

C语言从入门到精通 第十一章(文件操作)

写在前面: 本系列专栏主要介绍C语言的相关知识,思路以下面的参考链接教程为主,大部分笔记也出自该教程。除了参考下面的链接教程以外,笔者还参考了其它的一些C语言教材,笔者认为重要的部分大多都会用粗体标注&#xf…

C++ Qt开发:QFileSystemModel文件管理组件

Qt 是一个跨平台C图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用QFileSystemModel组件实现文件管理器…

HelpLook 和 confluence:创建知识库我选HelpLook

企业要想快速创建知识库,最好的方法就是利用好工具。而市面上创建知识库的平台多而繁杂,无法在最快时间内判断哪一个是最适合企业解决问题的。HelpLook和confluence功能相似,多数人无法判断并做出最佳选择,今天就跟着LookLook同学…

1688商品详情数据丨工厂详情数据丨店铺详情数据

1688商品详情数据、工厂详情数据以及店铺详情数据是商家在阿里巴巴1688平台上进行运营和决策的重要参考。这些数据涵盖了商品的详细信息、工厂的生产能力和信誉情况,以及店铺的经营状况和口碑评价,为商家提供了全方位的市场洞察和竞争优势。 请求示例&a…

Flutter学习9 - http 中 get/post 请求示例

1、配置 http pubspec.yaml dependencies:http: ^0.13.4flutter:sdk: flutterhttp 库最新插件版本查看:https://pub.dev/packages/http不一定要用最新版本 http,要使用项目所能支持的版本 .dart import package:http/http.dart as http;2、示例 &a…

基于UDP实现直播间聊天的功能

需求:软件划分为用户客户端和主播服务端两个软件client.c和server.c 用户客户端负责:1.接收用户的昵称2.接收用户输入的信息,能够将信息发送给服务端3.接收服务端回复的数据信息,并完成显示主播服务端负责:1.对所有加入直播间的用…

基于uniapp cli项目开发的老项目,运行报错path.replace is not a function

项目:基于uniapp cli的微信小程序老项目 问题:git拉取代码,npm安装包时就报错; cnpm能安装成功包,运行报错 三种方法尝试解决: 更改代码,typeof pathstring的话,才走path.replace…

mysql的语法总结2

命令: mysql -u 用户名 -p mysql登录 命令:create database u1 创建数据库u1 查询数据库 使用数据库u1 创建表department 查询表department ALTER TABLE 表名 操作类型; 操作类型可以有以下的操作: 添加列&#x…

【算法 高级数据结构】树状数组:一种高效的数据结构(一)

🚀个人主页:为梦而生~ 关注我一起学习吧! 💡专栏:算法题、 基础算法~赶紧来学算法吧 💡往期推荐: 【算法基础 & 数学】快速幂求逆元(逆元、扩展欧几里得定理、小费马定理&#x…

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK实现双快门采集两张曝光时间非常短的图像(C#)

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK实现双快门采集两张曝光时间非常短的图像(C#) Baumer工业相机Baumer工业相机定序器功能的技术背景Baumer工业相机通过NEOAPI SDK使用定序器功能预期的相机动作技术限制定序器的工作原理 Baumer工业相机通过…

20个Python函数程序实例

前面介绍的函数太简单了: 以下是 20 个不同的 Python 函数实例 下面深入一点点: 以下是20个稍微深入一点的,使用Python语言定义并调用函数的示例程序: 20个函数实例 简单函数调用 def greet():print("Hello!")greet…

WPF Border控件 基本使用

Border 基本使用 1单线效果 代码&#xff1a; <Border Grid.Row"0" BorderThickness"0,0,0,1" BorderBrush"Red" /> 说明&#xff1a; BorderThickness"0,0,0,1" 可以分别设置四条边&#xff0c;顺序是&#xff1a;左 上 右…

【微信小程序】基本语法

目录 一、列表渲染&#xff08;包括wx:for改变默认&#xff09; 二、事件冒泡和事件捕获 三、生命周期 一、列表渲染&#xff08;包括wx:for改变默认&#xff09; 1、列表渲染(wx-for、block 改变默认wx:for item等) <view> {{msg}} </view> //渲染跟普通vu…