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

news/2025/1/17 5:52:20/

一、前言

  宏在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.ppmy.cn/news/1202567.html

相关文章

YOLO目标检测——昏暗车辆检测数据集【含对应voc、coco和yolo三种格式标签】

实际项目应用:智能交通监控系统、驾驶辅助系统、城市安全监控、自动驾驶系统以及路况分析与规划等数据集说明:昏暗车辆检测数据集,真实场景的高质量图片数据,数据场景丰富,含有图片汽车、卡车、公共汽车标签说明&#…

SpringBoot整合Kafka (二)

📑前言 本文主要讲了SpringBoot整合Kafka文章,如果有什么需要改进的地方还请大佬指出⛺️ 上文链接:SpringBoot整合Kafka (一) 🎬作者简介:大家好,我是青衿🥇 ☁️博客首页:CSDN主页…

Direct3D地形绘制基础

高度图 用高度图来描述地形中的丘陵和山谷,高度图其实就是一个数组,该数组每个元素都指定了地形方格中某一个特定顶点的高度值。通常将高度图视为一个矩阵,这样高度图中的元素就与地形栅格中的顶点一一对应。 高度图被保存在磁盘中,通常为其每个元素元素只分配一个字节存…

稳定细胞系构建技术介绍

抗体药物的开发是一个非常复杂的过程,构建适用于工业生产的高表达的稳定细胞株是抗体药工艺开发的起点和基础。一株稳定高产的工程细胞株不仅能显著增加单位体积产量,降低生产成本,还可以降低下游纯化工艺复杂度,确保获得安全&…

NVIDIA Jetson SOC 内存分配策略

CPU 是Host, GPU 是Device, 系统内存分配策略如下: 这段话的翻译如下: 集成的GPU会和CPU以及其他Tegra引擎共享DRAM(动态随机存储器),并且CPU可以通过将DRAM的内容移动到交换区域(SWAP area)或者相反来控制…

手机玻璃盖板为什么需要透光率检测

手机盖板,也称为手机壳或保护套,是一种用于保护手机外观和延长使用寿命的装置。它们通常由塑料、硅胶、玻璃或金属等材料制成,并固定在手机外壳上,其中任何一个工序出现差错,都有可能导致手机盖板产生缺陷,例如漏油、透…

Android 12 S 系统开机流程分析(一)

开机有好几种方式启动,本文主要讲的是按Power键开机流程。 本文参考AOSP 12原生代码,链接为:AOSP 12 Searchhttp://aospxref.com/android-12.0.0_r3/ 目录 1. BootLoader加载 2. kernel启动 3. init进程启动 3.1 FirstStageMain 3.1.1…

ESP8266:物联网时代的连接神器

一、引言 在当今的物联网时代,智能设备与互联网的连接已经成为日常生活中不可或缺的一部分。而在这股浪潮中,ESP8266作为一个低成本、高效率的Wi-Fi芯片模块,扮演着举足轻重的角色。本文将为你揭示ESP8266的魅力,并探讨其在物联网…