【C语言】预处理常见知识详解(宏详解)

文章目录

  • 1、预定义符号
  • 2、define
    • 2.1 define 定义常量
    • 2.2 define 定义宏
  • 3、#和##
    • 3.1 **#**
    • 3.2 **##**
  • 4、条件编译(开关)


1、预定义符号

在C语言中内置了一些预定义符号,可以直接使用,这些符号实在预处理期间处理的,并且这些符号都是C语言ANSIC里收集的

在这里插入图片描述

但是在笔者的VS2022里不完全支持ANSIC的所有预定义符号

在这里插入图片描述

这里把这里的预定义处理STDC都打印了一遍,证明都可以实现,但是当我们打印STDC时会出现
在这里插入图片描述
由此可见随着编译器版本的升级有些C语言内置预定义会被忽视掉

2、define

2.1 define 定义常量

基本语法

#define name stuff

以下举例

#define MAX 1000//
#define reg register//为 register这个关键字,创建一个简短的名字/用更形象的符号来替换一种实现
#define do_forever for(;;)//定义函数,但是这个会造成死循环
#define CASE break;case//在写case语句的时候自动把 break写上。
#define DEBUG PRINT printf("file:%s\tline:%d\t\date:%s\ttime:%s\n",\__FILE__,-__LINE__,\__DATE__,__TIME__)
//如果定义的 stuff过长,可以分成几行写,除了最后一行外,每行的后面都加一个反斜杠(续行符),
//相当于下一行链接在‘\’处

思考:需要在定义后加上“;”吗?
例如:

#define MAX 1000
#define MAX 1000;

建议是不加上,可能会导致原来语句顺序发生错乱
假如上上面的MAX 1000最后加上了一个分号就会导致以下的运行情况

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

这种情况下,相当于if后面跟了两条语句,但是如果没有大括号的情况下,是不允许有多条语句的,所以这会导致if语句加执行语句max = MAX;,后跟了一条空语句,这会导致else前面断开,产生语法错误。

2.2 define 定义宏

#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(define macro)。

申明方式

#define name( parament-list ) stuff

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

  • 注意1:parament-list 的左括号必须紧贴在name的右边,一旦有空格在中间,就会让宏判定 ( parament-list ) 属于后面的 stuff

  • 注意2:宏一旦运行后会直接替换 parament-list 的内容到stuff里, stuff 及 parament-list 里的计算符的优先级就可能会导致计算顺序发生变化,
    所以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时由于参数中的操作符或邻近操作符之间不可预料的相互作用。

例如,现在有这样一个宏

#define double(x) x*x

没有注意用括号区分优先级的话,当 x 为 x+1 时,
这个宏的运算的顺序就是 x+1*x+1,即 x + x +1,最终导致结果发生较大偏差
但如果我们定义宏为

#define double(x) (x)*(x)

就不会在导致这种情况

  • 注意3:当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险,导致不可预测的后果。
    副作用就是表达式求值的时候出现的永久性效果。例如:++ , – 等符号

以下举例

#define MAX(X,Y) ((X)>(Y)?(X):(Y))int main()
{int a = 3;int b = 5;int m = MAX(a++, b++);//相当于替换成//int m = MAX(a++,b++) ((a++)>(b++)?(a++):(b++))//a++和b++各会执行两次printf("m = %d\n", m);//6printf("a = %d\n", a);//4printf("b = %d\n", b);//7return 0;
}

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

  1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。
  2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。
  3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。

注意

  1. 宏参数和#define 定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。
  2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。

宏和函数的对比
在这里插入图片描述

命名规则
一般来讲函数的宏的使用语法很相似。所以语言本身没法帮我们区分二者那我们平时的一个习惯是:

把宏名全部大写
函数名不要全部大写

其中内置宏 offsetof 比较特殊,它是红,但是全部小写,它的作用是计算结构体成员相对结构体起始位置的偏移量

#undef
用来移除一个宏定义

例如下图
在这里插入图片描述
原来没有移除 MAX 的时候,是可以打印出来的,但是一移除后就显示未定义标识符。


3、#和##

3.1 #

#运算符将宏的一个参数转换为字符串字面量。它仅允许出现在带参数的宏的替换列表中。
#运算符所执行的操作可以理解为”字符串化“。

例如:当我们有一个变量 int a = 10;的时候,我们想打印出:the value of ais 10
就可以写下面这个宏

#define PRINT(n) printf("the value of "#n " is %d", n);

当我们把a替换到宏的体内时,就出现了#a,而#a就是转换为"a”,时一个字符串代码就会被预处理为:

printf("the value of ""a" " is %d", a);

结果就是

the value of a is 10

3.2 ##

##可以把位于它两边的符号合成一个符号,它允许宏定义从分离的文本片段创建标识符。 ## 被称为记号粘合
这样的连接必须产生一个合法的标识符。否则其结果就是未定义的。
这里我们想想,写一个函数求2个数的较大值的时候,不同的数据类型就得写不同的函数。

比如,我们相要写下面这两个函数,但是要不断地写他们的类型名,这里我们可以利用宏

int int_max(int x, int y)
{return x > y ? x : y;
}
float float_max(float x, float y)
{return x > y ? x:y;
}

我们相要写上面这两个函数,但是要不断地写他们的类型名,这样太繁琐了,这里我们可以利用宏

//宏定义
#define GENERIC_MAX(type) \
type type##_max(type x, type y)\
{ \
return (x>y?x:y); \
}

其中 ## 的作用是链接type和后面的_max,否则,当type被输入后,type_max 就会被认为时一个,使得函数名一直是 type_max

定义好宏后,我们放入类型名进去,就会产生新的函数名,然后可以进行使用

GENERIC_MAX(int) //替换到宏体内后int##_max ⽣成了新的符号 int_max做函数名
GENERIC_MAX(float) //替换到宏体内后float##_max ⽣成了新的符号 float_max做函数名int main()
{
//调⽤函数
int m = int_max(2, 3);
printf("%d\n", m);
float fm = float_max(3.5f, 4.5f);
printf("%f\n", fm);
return 0;
}

最终结果是

3
4.500000

4、条件编译(开关)

当我们在调试时需要写一些语句辅助,但是正式发布时可能是不带的,我们一遍在正式使用时会注释掉,但这仅适用于小型代码,一旦代码量达到一个恐怖速度,就可能会有缺漏,并造成巨大的工作量,所以就用到了部分条件编译,用作开关

例如

#include <stdio.h>
#define __debug__
int main()
{int i = 0;int arr[10] = { 0 };for (i = 0; i < 10; i++){arr[i] = i;
#ifdef __debug__printf("%d\n", arr[i]);//为了观察数组是否赋值成功。
#endif //__debug__}return 0;
}

这里的代码,中间那条输出就是调试时观察用的,我们在开头定义宏,一旦不需要用掉,只需要把宏去了,就不会运行这行代码,这种方法用在代码很长的时候很有用,用做开关。

除了这个 #ifdef 还有很多别的

1.
#if 常量表达式
//...
#endif
//常量表达式由预处理器求值。
如:
#define __DEBUG__ 1
#if __DEBUG__
//..
#endif2.多个分⽀的条件编译
#if 常量表达式
//...
#elif 常量表达式
//...
#else
//...
#endif3.判断是否被定义
#if defined(symbol)
#ifdef symbol
#if !defined(symbol)
#ifndef symbol4.嵌套指令
#if defined(OS_UNIX)
#ifdef OPTION1
unix_version_option1();
#endif
#ifdef OPTION2
unix_version_option2();
#endif
#elif defined(OS_MSDOS)
#ifdef OPTION2
msdos_version_option2();
#endif
#endif

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

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

相关文章

ssm网上订餐管理系统开发mysql数据库web结构java编程计算机网页源码eclipse项目采用线性算法

一、源码特点 ssm 网上订餐管理系统是一套完善的信息系统&#xff0c;结合springMVC框架完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模…

【计算机网络】第 9 问:四种信道划分介质访问控制?

目录 正文什么是信道划分介质访问控制&#xff1f;什么是多路复用技术&#xff1f;四种信道划分介质访问控制1. 频分多路复用 FDM2. 时分多路复用 TDM3. 波分多路复用 WDM4. 码分多路复用 CDM 正文 什么是信道划分介质访问控制&#xff1f; 信道划分介质访问控制&#xff08;…

主流公链 - Filecoin

探索Filecoin&#xff1a;去中心化存储网络 1. Filecoin简介 Filecoin是一个去中心化的存储网络&#xff0c;旨在通过区块链技术实现全球性的分布式文件存储和检索市场。Filecoin允许用户将文件存储在网络中的节点上&#xff0c;并通过加密、分片和复制等技术保证数据的安全性…

OpenHarmony开发之WebGL开发指导与介绍

WebGL的全称为Web Graphic Library(网页图形库)&#xff0c;主要用于交互式渲染2D图形和3D图形。目前OpenHarmony中使用的WebGL是基于OpenGL裁剪的OpenGL ES&#xff0c;可以在HTML5的canvas元素对象中使用&#xff0c;无需使用插件&#xff0c;支持跨平台。WebGL程序是由JavaS…

hadoop-3.1.1分布式搭建与常用命令

一、准备工作 1.首先需要三台虚拟机&#xff1a; master 、 node1 、 node2 2.时间同步 ntpdate ntp.aliyun.com 3.调整时区 cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 4.jdk1.8 java -version 5.修改主机名 三台分别执行 vim /etc/hostname 并将内容指定为…

Mysql数据库-DQL查询

Mysql数据库-DQL基本查询 1 DQL基本查询1.1 基础查询1.2 WHERE子句1&#xff09;算术运算符2&#xff09;逻辑运算符3&#xff09;比较运算符A&#xff09;BETWEEN... AND ...B&#xff09;IN(列表)C&#xff09;NULL值判断 4&#xff09;综合练习 2 DQL高级查询2.1 LIKE 模糊查…

2024年北京事业单位报名照片要求,注意格式

2024年北京事业单位报名照片要求&#xff0c;注意格式

HarmonyOS 应用开发之ExtensionAbility组件

ExtensionAbility组件是基于特定场景&#xff08;例如服务卡片、输入法等&#xff09;提供的应用组件&#xff0c;以便满足更多的使用场景。 每一个具体场景对应一个 ExtensionAbilityType&#xff0c;开发者只能使用&#xff08;包括实现和访问&#xff09;系统已定义的类型。…

金属氧化物压敏电阻的冲击破坏机理高能压敏电阻分析

以氧化锌为主的金属氧化物阀片在一定的电压和电流作用下的破坏可分为热破坏和冲击破坏两类。 热破坏是指氧化锌电阻在交流电压持续作用时发生的破坏,即由于阀片在交流作用下的发热超过了其散热能力而导致的热平衡失控的现象。交流引起的热破坏可以分为几种不同情况:一种是由于…

【Redis教程0x08】详解Redis过期删除策略内存淘汰策略

引言 Redis的过期删除策略和内存淘汰策略是经常被问道的问题&#xff0c;这两个机制都是做删除操作&#xff0c;但是触发的条件和使用的策略是不同的。今天就来深入理解一下这两个策略。 过期删除策略 Redis 是可以对 key 设置过期时间的&#xff0c;因此需要有相应的机制将…

[flink 实时流基础系列]揭开flink的什么面纱基础一

Apache Flink 是一个框架和分布式处理引擎&#xff0c;用于在无边界和有边界数据流上进行有状态的计算。Flink 能在所有常见集群环境中运行&#xff0c;并能以内存速度和任意规模进行计算。 文章目录 0. 处理无界和有界数据无界流有界流 1. Flink程序和数据流图2. 为什么一定要…

JMM Java内存模型

JMM本身是一个抽象的概念,不是真实存在的,它仅仅是一种规定或者说是规范 1.用来实现线程和主内存直接的抽象关系 2.屏蔽各个硬件平台和操作系统的内存访问差异,使得java程序在各种平台都能达到一致的内存访问效果 JMM的三大特性 可见性 多线程环境下,某个线程修改了变量…

构建智能未来:探索AI人工智能产品业务架构的创新之路

随着人工智能技术的快速发展&#xff0c;AI人工智能产品在各行各业中扮演着越来越重要的角色。本文将深入探讨AI人工智能产品业务架构的创新之路&#xff0c;探讨如何构建智能未来的商业生态。 ### AI人工智能产品业务架构的重要性 AI人工智能产品的业务架构是支撑产品成功的…

RTSP应用:实现视频流的实时推送

在实现实时视频流推送的项目中&#xff0c;RTSP&#xff08;Real Time Streaming Protocol&#xff09;协议扮演着核心角色。本文将指导你通过安装FFmpeg软件&#xff0c;下载并编译live555&#xff0c;以及配置ffmpeg进行视频流推送&#xff0c;来实现一个基本的RTSP流媒体服务…

element-ui 自定义点击图标/文本/按钮触发el-date-picker时间组件,不使用插槽

天梦星服务平台 (tmxkj.top)https://tmxkj.top/#/ 1. 图片预览 2.上代码 2.1html <el-button class"hide_input" size"small"><svg t"1711608996149" class"icon" viewBox"0 0 1024 1024" version"1.1"…

Haproxy2.8.1+Lua5.1.4部署,haproxy.cfg配置文件详解和演示

目录 一.快速安装lua和haproxy 二.配置haproxy的配置文件 三.配置haproxy的全局日志 四.测试负载均衡、监控和日志效果 五.server常用可选项 1.check 2.weight 3.backup 4.disabled 5.redirect prefix和redir 6.maxconn 六.调度算法 1.静态 2.动态 一.快速安装lu…

【Redis】Redis 内存管理,Redis事务,bigkey和hotkey

目录 Redis 内存管理 缓存数据设置过期时间&#xff1f; Redis 是如何判断数据是否过期的呢&#xff1f; 过期删除策略 内存淘汰机制 主从模式下对过期键的处理&#xff1f; LRU和LFU的区别 Redis事务 定义和原理 Redis 事务的注意点&#xff1f; 为什么不支持回滚&a…

网络编程之数据包套接字

数据报套接字提供一种无连接、不可靠的服务。该服务并不能保证数据传输的可靠性,数据有可能在传输过程中丢失或出现数据重复&#xff0c;且无法保证顺序地接收到数据。使用UDP协议进行数据的传输。 服务端代码 //服务端 #include <stdio.h> #include <winsock2.h>…

3D目标检测综述笔记

3D Object Detection for Autonomous Driving: A Review and New Outlooks https://arxiv.org/pdf/2206.09474.pdf 目录 0.background​编辑 1.1表示形式 1.2感知输入 1.3数据集 1.4评估指标 1. LiDAR-based 3D Object Detection 2.数据表征 2.1 point-based​ 2.1.…

2024年天府杯A题论文免费分享,全网首发

天府杯免费分享资料&#xff08;A题论文代码&#xff09;链接&#xff1a;https://pan.baidu.com/s/17QtYt036ORk1xGIDi0JSew 提取码&#xff1a;sxjm 摘要 在近年来&#xff0c;随着科技的快速发展和社会经济的不断进步&#xff0c;科学研究的作用和地位日益凸显。本文基于…