C语言-预处理详解
1.预处理符号
C语言中设置了一些预定义符号,可以直接使用,预定义符号是在预处理期间处理的。
__FILE__//代表当前进行编译的源文件
__LINE__//文件当前行号
__DATE__//文件当前日期
__TIME__//文件当前时间
__STDC__//如果编译器遵循ANSIC,其值为1,否则未定义
接下来,我们可以试验一下:
#include<stdio.h>int main()
{printf("%s\n",__FILE__);printf("%s\n",__DATE__);printf("%s\n",__TIME__);printf("%d\n",__LINE__);return 0;
}
经过预处理之后,代码变成了:
int main()
{printf("%s\n","test.c");//目前在编译的文件名printf("%s\n","July 19 2024");printf("%s\n","18:17:54");printf("%d\n",8);return 0;
}
2.#define定义字符常量
基本语法:
#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__)
思考:
在define定义标识符的时候,如果在末尾加上‘;’怎样?
比如:
#define MAX 1000
#define MAX 1000;
建议不要加‘;’,因为可能会导致一些问题。
例:
当用了:
printf("%d\n",MAX);
就会出问题。
如果是这个:
if(condition)max=MAX;
elsemax=0;
那么等替换之后,if和else之间就是两条语句,而没有大括号时if和else后面只能接一条语句,else就不知道是和哪个else匹配的,就会出现语法错误。
3.#define定义宏
#define机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或者定义宏(define macro)。
下面是其
定义方式:
#define name(parament-list) stuff
其中的parament-list是一个由逗号隔开的符号表,带表参数,它可能出现在stuff中。
注意:
参数列表的左括号必须与name紧邻,如果二者之间有任何的空白存在,参数列表就会解释为stuff的一部分。
举例:
#define f(x) x*x
4.带有副作用的宏参数
所谓的副作用就是在实现预想的结果的同时,影响了其他的结果。
当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险,导致不可预料的后果。
例如:
#define MAX(a,b) ((a)>(b)?(a):(b))
.....
int x=5;
int y=8;
int z=MAX(x++,y++);
5.宏替换的规则
在程序中扩展#define定义符号和宏时,需要涉及几个步骤。
1.在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,他们首先被替换。
2.替换的文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值替换。
3.最后,再对结果文本进行扫描,看看它是否包含任何由#define定义的符号。如果是,则重复上述处理过程。
注意:
1.宏参数和#define定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。
2.当预处理器搜索#define定义的符号时,字符串常量的内容并不被搜索。
例:
#define M 10
但是“MARY"中的M是不会被替换的。
6.宏与函数的对比
宏通常被应用于执行简单的运算。
比如在两个数中找到较大数。
#define MAX(a,b) ((a)>(b)?(a):(b))
而如果用函数来完成,有一下缺点:
1.用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间要多。所以在小型计算中,宏比函数在程序的规模和速度上要更胜一筹。
2.更为重要的是,函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使用,反之,宏可以适用于整型,长整型,浮点型等可以用>来比较大小的类型。宏的参数是类型无关的。
宏有些时候可以做到函数做不到的事。比如:宏的参数可以出现类型,而函数不可以:
#define MALLOC(num,type) (type*)malloc(num*sizeof(type))
和函数相比,宏的劣势:
1.每次使用宏时,一份宏定义的代码将插入到程序中。除非这段代码较短,否则可能大幅度增加程序的长度。
2.宏没法调试
3.宏由于是类型无关的,不够严谨。
4.宏可能带来运算符优先级的问题,导致程序容易出错。
至于第四点,有个例子:
#define MAX(a,b) a*b
//当a=3+1 b=1+2时
7.#和##
一.#
'#'运算符将宏的一个参数转换为字符串常量。它仅允许出现在带参数的宏的替换列表中。
‘#'运算符所执行的操作可以理解为“字符串量化”。
适用场景:
当我们想要打印出“The value of x is %d"的情况
例如:
The value of b is 12
The value of a is 1
而以上的语句大致相同,需要改变的是某个数据的名字以及数据的具体大小。
为了方便后面的讲解,我们需要补充一个知识点:
在c语言中,printf("Hello world!")与printf("Hello""world!”)的结果是一样的。
回到原来的问题:我们把这个语句定义为宏
即:
#define PRINT(n) printf("The value of"#x"is%d\n",x);
当我们使用这个宏时:
int a=1;
PRINTF(a);
就会变成:
The value of a is 1
而#x就是将x转化为"x"这个字符串。
如果还想在字符串中加一些内容,可以直接#内容。
注意:我们需要使用这个符号的一个原因是:宏在替换时,不会替换字符串内的内容。
二.##
'##'字符用在宏定义里可以把两个符号粘连在一起,合成一个符号。被称为记号粘合。
这样的连接产生的标识符必须是合法的,否则就是未定义的。
它有如下应用场景:
当我们想要找出两个数中的较小数时,不同的数据类型得写不同的函数,但是,这样的函数结构是类似的,于是,我们就想到用宏,然而,这些不同函数的名称也要随着参数改变,同时要是合法的,而宏的参数只有一个,那就是类型,所以,我们想到用记号粘合。
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 TYPE_MAX(type) \
type type##_max(type x,type y)\
{ \return (x>y?x:y); \
}
具体使用:
TYPE_MAX(int)
//在预编译中替换为:
//int_max(int x,int y)
//{
// return x>y?x:y;
}
TYPE_MAX(float)
//在预编译中替换为:
//float float_max(float x,float y)
//{
// return x>y?x:y;
//}int main()
{int m=int_max(2,3);float n=float_max(3.5f,4.5f);return 0;
}
8.命名约定
由于宏与函数的使用语法相似,所以语言上无法帮我们区分二者,所以我们通常用一下命名习惯区分:
1.宏的全名全部大写。
2.函数名不要全部大写。
当然,这个规定不一定要遵守,c语言本身就有一些没有遵守,例如:
offsetof———宏:计算结构体成员相较于结构体起始位置的偏移量。
9.#undef
这个指令用于移除一个宏定义。是可以直接写入主函数的,不过需要注意的是:它与#define相同,不用单独加';'来表示语句的结束。
例如:
#define NAME 10int main()
{#undef NAMEreturn 0;
}
10.命令行定义
许多编译器提供了一种能力,允许在命令行中定义符号,用于启动编译过程。
例如:当我们根据同一个源文件要编译出一个程序的不同版本时,这个能力就能起到作用。
假如某个程序中声明了一个某长度的数组,如果机器的内存有限,我们需要一个很小的数组,但是另一个机器的内存大些,我们需要一个更大的数组时,就可以利用这个能力。
好处:代码可以根据需求快速调整。
11.条件编译
利用条件编译指令我们可以很方便的编译或放弃一条或一组语句。
例如:某些语句起到的是调试作用,我们希望在某些条件下使用。
#define _DEBUG_//当不想要ifdef后面的语句时,就注释掉这句int main()
{#ifdef _DEBUG_printf("6\n");#endifreturn 0;
}
常见的条件编译指令:
#if 常量表达式 //如果为假,后面的语句就不参与编译//...
#endif
//注意:一定要以#endif结尾//多分支条件编译#if 常量表达式//...
#elif 常量表达式//...
#else//...
#endif//判断是否被定义
#if defined(symbol)
#ifdef symbol#if !definede(symbol)
#ifndef symbol
注意:这些指令是可以相互嵌套的
12.头文件的包含
一.本地文件的包含:
#include"filename"
查找方式:先在源文件下的目录里找,如果该文件未被找到,编译器就会像找库函数一样在标准位置查找头文件。
如果找不到就显示编译错误。
二.库文件包含
#include<filename>
查找方式:直接在标准文件下查找,如果找不到就提示编译错误。
当然,库文件也可以用""包含,不过,这样的话效率就会低一些,也会没那么容易区分本地文件和库文件。
三.嵌套文件的包含
如果一个同文件被多次包含,编译器在预处理时就会多次替换头文件的内容,这样的重复包含对编译的压力很大。所以,我们可以使用一些方法避免这样的情况出现。
利用条件编译防止重复包含。
方法一:
在每个头文件里加上:
#ifndef __TEST_H__
#define __TEST_H__
//头文件中的内容
#endif
方法二:
在每个头文件中加上:
#pragma once
13.其他预处理指令
目前不想写了,可参考《C语言深度剖析》这本书。
相关文章:
C语言-预处理详解
1.预处理符号 C语言中设置了一些预定义符号,可以直接使用,预定义符号是在预处理期间处理的。 __FILE__//代表当前进行编译的源文件 __LINE__//文件当前行号 __DATE__//文件当前日期 __TIME__//文件当前时间 __STDC__//如果编译器遵循ANSIC,…...
计算机网络-VLAN间通信(三层通信)模拟实现
目录 VLAN基础知识VLAN和普通LAN区别划分VLAN的原因 实现VLAN间的通信(三层通信)方案一:多臂路由方案二:单臂路由方案三:三层交换机 VLAN基础知识 VLAN(Virtual Local Area Network,虚拟局域网…...
【JAVA】数据类型及变量
🎉欢迎大家收看,请多多支持🌹 🥰关注小哇,和我一起成长🚀个人主页🚀 Java的数据类型 可以分为两类,基本数据类型和引用数据类型 基本数据类型有4类8种,4类分别是整型 浮…...
微软蓝屏事件暴露的网络安全问题
目录 1.概述 2.软件更新流程中的风险管理和质量控制机制 2.1.测试流程 2.2.风险管理策略 2.3.质量控制措施 2.4.小结 3.预防类似大规模故障的最佳方案或应急响应对策 3.1. 设计冗余系统 3.2. 实施灾难恢复计划 3.3. 建立高可用架构 3.4. 类似规模的紧急故障下的响应…...
11 - FFmpeg - 编码 AAC
Planar 模式是 ffmpeg内部存储模式,我们实际使用的音频文件都是Packed模式的。 FFmpeq解码不同格式的音频输出的音频采样格式不是一样。 其中AAC解码输出的数据为浮点型的 AV_SAMPLE_FMT_FLTP 格式,MP3 解码输出的数据为 AV_SAMPLE_FMT_S16P 格式(使用的…...
OS Copilot初体验的感受与心得
本文介绍体验操作系统智能助手OS Copilot后,个人的一些收获、体验等。 最近,抽空体验了阿里云的操作系统智能助手OS Copilot,在这里记录一下心得与收获。总体观之,从个人角度来说,感觉这个OS Copilot确实抓住了不少开发…...
Ajax学习笔记
文章目录标题 Ajax学习笔记axios使用axios请求拦截器axios响应拦截器优化axios响应结果 form-serialize插件图片上传HTTP协议请求报文相应报文接口文档 AJAX原理 - XMLHttpRequest使用XMLHttpRequestXMLHttpRequest - 查询参数查询字符串对象 XMLHttpRequest - 数据提交 事件循…...
医学深度学习与机器学习融合的随想
医学深度学习与机器学习融合的随想 近年来,深度学习(图像类)和机器学习在医学领域的应用取得了飞速发展,为医学影像分析、疾病诊断和预后预测等领域带来了革命性的变革。深度学习擅长从复杂数据中提取高层次特征,而机…...
坑人的macos tar 命令 (实际上是bsdtar)换用 gnu tar
周末 看着笔记本上好用的朗文当代高级词典(mac版)和其它两部词典,准备复制到黑苹果台式机上去。考虑到词典内容有太多小文件,普通复制传输太慢,毫无疑问用 tar 打包肯定快而且能保留原始文件的各种信息。命令如下: time tar czf …...
【SpringBoot3】全局异常处理
【SpringBoot3】全局异常处理 一、全局异常处理器step1:创建收入数字的页面step2:创建控制器,计算两个整数相除step3:创建自定义异常处理器step5:创建给用提示的页面step6:测试输入(10/0) 二、BeanValidato…...
vue-Treeselect
一、Node KeyTypeDescriptionid (required)Number | String用于标识树中的选项。其值在所有选项中必须是唯一的label (required)String用于显示选项childrennode[] | null声明一个分支节点。你可以: 1) 设置为由a组成的子选项数组。叶节点,b…...
【机器学习框架TensorFlow和PyTorch】基本使用指南
机器学习框架TensorFlow和PyTorch:基本使用指南 目录 引言TensorFlow概述 TensorFlow简介TensorFlow的基本使用 PyTorch概述 PyTorch简介PyTorch的基本使用 TensorFlow和PyTorch的对比结论 引言 随着深度学习的快速发展,机器学习框架在实际应用中起到…...
matlab 中的methods(Access = protected) 是什么意思
gpt版本 在 MATLAB 中,methods 是用于定义类方法的一部分。(Access protected) 是一种访问控制修饰符,它限制了方法的访问权限。具体来说,当你在类定义中使用 methods(Access protected) 时,你是在定义只有类本身及其子类可以访…...
【漏洞复现】Netgear WN604 downloadFile.php 信息泄露漏洞(CVE-2024-6646)
0x01 产品简介 NETGEAR WN604是一款由NETGEAR(网件)公司生产的无线接入器(或无线路由器)提供Wi-Fi保护协议(WPA2-PSK, WPA-PSK),以及有线等效加密(WEP)64位、128位和152…...
图像处理 -- ISP调优(tuning)的步骤整理
ISP调优流程培训文档 1. 硬件准备 选择合适的图像传感器:根据项目需求选择合适的传感器型号。搭建测试环境:包括测试板、光源、色彩卡和分辨率卡等。 2. 初始设置 寄存器配置:初始化传感器的寄存器设置,包括曝光、增益、白平衡…...
【中项】系统集成项目管理工程师-第4章 信息系统架构-4.2系统架构
前言:系统集成项目管理工程师专业,现分享一些教材知识点。觉得文章还不错的喜欢点赞收藏的同时帮忙点点关注。 软考同样是国家人社部和工信部组织的国家级考试,全称为“全国计算机与软件专业技术资格(水平)考试”&…...
node.js中nodemon : 无法加载和使用问题,这是由于windows安全策略影起的按如下操作即可
1、用管理员权限打开vscode 2、文件终端中打开,输入 Set-ExecutionPolicy -Scope CurrentUser 3、再输入RemoteSigned 4、使用get-ExecutionPolicy查看权限,可以看到变为了RemoteSigned 重启问题解决...
【SD】 Stable Diffusion(SD)原理详解与ComfyUI使用 2
Stable Diffusion(SD)原理详解与ComfyUI使用 Stable Diffusion(SD)原理详解与ComfyUI使用1. SD整体结构2. Clip(文本编码器)3. Unit(生成模型)4. VAE(变分自编码器&#…...
【学习笔记】无人机系统(UAS)的连接、识别和跟踪(七)-广播远程识别码(Broadcast Remote ID)
目录 引言 5.5 广播远程识别码(Broadcast Remote ID) 5.5.1 使用PC5的广播远程识别码 5.5.2 使用MBS的广播远程识别码 引言 3GPP TS 23.256 技术规范,主要定义了3GPP系统对无人机(UAV)的连接性、身份识别、跟踪及…...
VMware 虚拟机 ping 不通原因排查
目录 一、检查网络 二、重启虚拟机网络 因为最近遇到了一个比较奇怪的 ping 不通虚拟机的事,在此过程中,检查了很多的设置,故而写一篇文章记录下,如有 VMware 虚拟机 ping 不通可以尝试本文的排查方式。 下面以 VMware 虚拟机为…...
IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...
Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...
AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...
