C语言:对于宏的一些概念及技巧

news2024/9/29 21:24:26

一、前言

  宏在C语言中是一段有名称的代码段,在程序编译过程中,会将宏的内容被这段代码进行替换,常常用于定义一些常量、函数、代码块等,由于近年来发现许多公司进行面试时对于宏的面试题尤为多,故本文将对C语言中的宏的结构、使用以及注意事项进行详细介绍,有想法的小伙伴还可以在此基础上继续深入研究。

二、宏的基本结构

宏的基本结构如下:

在这里插入图片描述

例如:
#define  PI   3.1415         
#define  number  50         
#define  MAX(x , y ) ((x)>(y)?(x):(y)) 

三、宏的基本使用

1、不携带参数的宏的定义
格式:
#define   宏名     表达式
例如:
#define    PI    3.1415  //程序在预处理阶段会将PI替换为3.1415
注意事项:
1)宏定义实质只进行替换,不进行计算
(2)宏名之后的表达式可以是常数、条件语句、函数等,预处理程序对它不做任何检查,程序在编译时才对宏替换的内容进行检查
(3)宏定义不是说明或语句,在行末不需要添加分号,如果用户在行末添加分号,则连分号一起进行替换
例如:
#define   PI   3.1415   //将PI替换为“3.1415”
#define   PI   3.1415;   //将PI替换为“3.1415;”4)宏定义存在于全局,其作用域为全局作用域
例如:
xxx.c:
#include “stdio.h”
#include “stdlib.h”
#define  PI   3.1415   //该宏存在于全局
int main()
{
printf(“PI=%f\n”,PI);
}5)宏定义允许发生嵌套,即一个宏可以使用另外一个已经存在的宏
格式:
#define   number   50 ;  
#define   sum      number*50  ; //宏的嵌套,将number替换成50,将sum替换成number*50

2、携带参数的宏的定义
定义:
#define    宏名(参数1,参数2.....)    表达式
调用:
宏名(实参1,实参2...........)

例如:
定义:
#define   getMax(a,b)  a>b?a:b  //将getMax(a,b)替换成a>b?a:b的结果
调用:
int  num=getMax(10,20)  ;//调用之后getMax(10,20)返回最大值20
注意事项:

(1)考虑优先级问题,即如果宏定义中的表达式涉及运算符的优先级问题,需要用户及时考虑

第一种:考虑表达式中涉及优先级问题

例如:

代码如下:
#define   getSum(a,b)   a*b   
int  result1=getSum(40,20) ;
int  result2 =getSum(10+30,20);

运行结果如下:

通过上面代码发现,最终计算的结果不一致,下面来分析一下原因:

1#define   getSum(a,b)   a*b
int  result1=getSum(40,20) ; //目标是计算40*20的结果,编译器在执行时,将a替换为40,将b替换为20,故a*b的值为40*20,即800
2#define   getSum(a,b)   a*b
int  result2 =getSum(10+30,20);//目标是计算(10+30)*20的结果,但是编译器在执行时,将a替换为10+30,将b替换为20,这时候a*b的值为10+30*20,即考虑优先级先执行乘法运算,再执行加法运算,所以结果为610
总结:
  通过以上1)和2)两点,我们如何进行修改才能达到最初的目标40*20=800的结果?
修改如下:
代码:
#define    getMax(a,b)    (a) *b
int result1=getMax(10+30,20)  //计算结果:(10+30)*20=800
int result2=getMax(40,20)     //计算结果:(40)*20=800
运算结果:

在这里插入图片描述

第二种:考虑宏替换返回结果后涉及优先级问题

例如:
代码:
#define   getSum(a,b)   a+b   
int  result1=getSum(40,20)*3 ;//目标是计算(40+20)*3=180
运算结果:

在这里插入图片描述

通过上面代码发现,最终计算的结果是100,而不是180,下面来分析一下原因:
#define   getSum(a,b)   a+b   
int  result1=getSum(40,20)*3 ;//编译器在执行时,将a替换为40,将b替换为20,这时候result1=40+20*3,即先执行20*3=60,再执行40+60=100
总结:

  通过上面代码,我们如何实现最初的目标(40+20)*3=180?

修改如下:
#define    getSum(a,b)   (a+b)
int result1=getSum(40,20)*3  //计算结果:(40+20)*3=180
运行结果:

在这里插入图片描述
(2)带参数的宏与函数的区别
1)宏比函数的运算速度快

使用宏:

在这里插入图片描述

使用函数:

在这里插入图片描述
2)宏不需要执行形参类型,而函数需要指定形参类型

例如:
宏:
#define  getMax(a,b)   a>b?a:b   //a和b没有指定类型
函数:
void function(int a, int b);          //a和b需要指定类型

3)宏不能够进行调试(因为宏替换工作是在预处理阶段)
4)宏不能实现递归
5)预处理符号“#”,如果设置一个表示将宏参数转为字符串,也通常被称为字符串转化运算符;如果设置两个表示将两个宏参数进行连接,称为连接运算符

一个“#”格式:
#define   get_Str(x)    #x       //参数x将转换为字符串进行输出

在这里插入图片描述

两个“#”格式:
#define    get_str(a,b)    a##b    //将参数a和b进行连接后返回

在这里插入图片描述

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

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

相关文章

基于springboot实现招生平台管理系统项目【项目源码+论文说明】

基于springboot实现招生管理系统演示 摘要 在Internet高速发展的今天,我们生活的各个领域都涉及到计算机的应用,其中包括招生管理系统的网络应用,在外国招生管理系统已经是很普遍的方式,不过国内的管理网站可能还处于起步阶段。招…

使用Keepalived实现双机热备,实现服务高可用

安装(所有节点) yum -y install keepalived修改配置 vi /etc/keepalived/keepalived.conf :set nu //显示行号 :35 dG // 删除35行以后的所有行ip a将master1虚拟机挂起,再次执行ip a 看vip是否漂移到另一台虚拟机worker1 漂移了&…

一图搞懂傅里叶变换(FT)、DTFT、DFS和DFT之间的关系

自然界中的信号都是模拟信号,计算机无法处理,因此我们会基于奈奎斯特定理对模拟信号采样得到数字信号。 但是我们发现,即便是经过采样,在时域上得到了数字信号,而在频域上还是连续信号。 因此我们可以在时域中选取N点…

Softing TDX——设计模板

| 高质量的设计模板——减少开发诊断仪所需的工作量 现今,用户对诊断仪的界面和操作理念提出了更高的要求。一个直观的用户界面既能减少用户熟悉诊断仪的时间,又能减少在日常工作中进行诊断任务的时间。然而,创建一个精巧又独立于平台的诊断…

apollo docker搭建

1 mysql搭建 先需要一个mysql,mysql我使用的是5.7,搭建过程忽略 2 数据导入 我们需要从github上下载apolloportaldb.sql, apolloconfigdb.sql 2个sql 随后cp apolloconfigdb.sql apolloconfigdbUat.sql cp apolloconfigdb.sql apolloconfigdbDev.sq…

翻转二叉树(C++解法)

题目 给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。 示例 1: 输入:root [4,2,7,1,3,6,9] 输出:[4,7,2,9,6,3,1]示例 2: 给你一棵二叉树的根节点 root ,翻转这棵二叉树&…

STM32G0+EMW3080+阿里云飞燕平台实现单片机WiFi智能联网功能(三)STM32G0控制EMW3080实现IoT功能

项目描述:该系列记录了STM32G0EMW3080实现单片机智能联网功能项目的从零开始一步步的实现过程;硬件环境:单片机为STM32G030C8T6;物联网模块为EMW3080V2-P;网联网模块的开发板为MXKit开发套件,具体型号为XCH…

chrome安装Vue Devtools插件以及无法添加来自此网站的应用问题

chrome安装Vue Devtools插件以及无法添加来自此网站的应用问题 问题背景 Chrome Vue插件是一款可以帮助前端开发人员在浏览器中实时查看和编辑Vue组件和数据的工具。给前端开发人员提供了极大的便利。本文将介绍Chrome浏览器中如何安装Devtools插件。 问题分析 &#xff08…

SpringBoot上传与下载文件

使用SpringBoot的虚拟路径映射。 Config中的类 import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import o…

iconfont 图标使用

(1)在阿里巴巴矢量图标库注册账号,然后让同伴拉你进项目iconfont-阿里巴巴矢量图标库 (2) 点击资源管理 - 我的项目 - 可以看见该项目的图标了 (3)点击上传图标至项目 - 可以上传图标 使用图标 &#x…

使用高德地图获取定位报错:INVALID_USER_SCODE(无效用户代码)

1. 确定自己已经申请了相关应用的key&#xff0c;这里有两个key 一个是应用的Key&#xff0c;一个是安全密钥 2. 应用key一般是发送请求的是后通过key"xxx"发送 3. 安全密钥要在head里加入进去 <script type"text/javascript">window._AMapSecuri…

CocosCreator使用物理引擎和回调

在2d中开启碰撞需要在项目设置–功能裁剪–2D物理系统【选择 基于Box2D的2D物理系统】 如果想要两个物体碰撞&#xff0c;则需要添加刚体和碰撞【&#xff01;&#xff01;重点】 设置刚体类型 可以设为四种&#xff0c; Static 静态刚体&#xff0c;零质量&#xff0c;零速度…

《微服务架构设计模式》之三:微服务架构中的进程通信

概述 交互方式 客户端和服务端交互方式可以从两个维度来分&#xff1a; 维度1&#xff1a;一对一和多对多 一对一&#xff1a;每个客户端请求由一个实例来处理。 一对多&#xff1a;每个客户端请求由多个实例来处理。维度2&#xff1a;同步和异步 同步模式&#xff1a;客户端…

如何评价现在的CSGO游戏搬砖市场

如何评价现在的csgo市场&#xff1f; 其实整个搬砖市场&#xff0c;现在已经变得乌烟瘴气&#xff0c;散发着“恶臭”。我个人非常鄙视那些虚有其表&#xff0c;大小通吃的做法&#xff0c;那些甚至连搬砖数据都看不懂的人&#xff0c;也出来吹嘘着“实力强大&#xff0c;经验丰…

[架构之路-244]:目标系统 - 设计方法 - 软件工程 - 软件开发方法:结构化、面向对象、面向服务、面向组件的开发方法

目录 前言&#xff1a; 一、概述: 软件聚合的程度由简单到复杂 二、主要开发方法详见 2.1 结构化的开发方法 2.2 面对对象的开发方法 2.3 面向服务的开发方法 2.4 面向组件的开发方法 三、不同开发方法比较 3.1 结构化开发方法 3.2 面向对象(OOP)开发方法 3.3 面向服…

电源模块测试科普:如何检测电源模块的功率?测试方法是什么?

电源模块功率的重要性 功率是电源模块的一个重要指标。电源模块功率描述了电源的输出能力&#xff0c;即电源模块为电路或设备提供电能的大小&#xff0c;通常用来衡量电源模块的性能和效率。 电源功率直接影响着电子设备的性能和功能。电源模块功率越高&#xff0c;提供的电能…

模块化之CJS, AMD, UMD 和 ESM

[[toc]] 模块化优点 防止命名冲突代码复用高维护性CJS, AMD, UMD 和 ESM 历史 ES6之前,JS一直没有自己的模块体系后来社区出现了CommonJS和AMD,CommonJS 主要用于服务器(Node)AMD 主要用于浏览器ES6引入了ESM到此,JS终于有了自己的模块体系,基本上可以完全取代CJS和AMD…

TCP流量控制和拥塞控制

文章目录 流量控制拥塞控制 流量控制 当发送方发送速率大于接收方的处理速率时&#xff0c;接收方会把数据包放入缓冲区&#xff0c;当缓冲区满了&#xff0c;就只能将数据包丢弃。为了应对这种情况&#xff0c;流量控制就可以大展身手了 流量控制的作用对象是发送方和接收方 …

【计算文献解读】ACS Catal.:塑料垃圾回收利用中的均相催化

合理的塑料回收对于解决与塑料垃圾相关的环境挑战至关重要&#xff0c;而在各种回收方法中&#xff0c;化学回收&#xff0c;特别是通过均相催化&#xff0c;有望将塑料垃圾转化为有价值的产品。由于聚烯烃链的结构不均匀性和功能化&#xff0c;聚合物废物对催化循环提出了挑战…

AI人工智能大模型业务到底有多烧钱?

AI大模型业务确实是一个非常烧钱的行业。首先&#xff0c;大模型的训练需要大量的计算资源。 这些模型通常由数百万个参数组成&#xff0c;训练它们需要大量的计算能力和存储空间。这意味着公司需要购买大量的高性能服务器、图形处理单元和存储设备&#xff0c;这些都是非常昂…