【C语言】预处理详解(下)

文章目录

  • 前言
  • 6. 宏和函数的对比
  • 7. #和##
    • 7.1 #运算符
    • 7.2 ##运算符(运用较少,了解即可)
  • 8. 命名的约定
  • 9. #undef (了解即可)
  • 10. 条件编译(重点)
  • 11. 头文件的包含
    • 11.1 头文件被包含的方式:
      • 11.1.1 本地文件包含
      • 11.1.2 库文件的包含

前言

我们接着详解预处理(上)内容给大家继续讲解预处理的有趣之处。

6. 宏和函数的对比

在详解预处理(上)我讲到定义宏时,如果比较两个数的大小,我们可以这样写一个宏:

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

当然我们也可以用函数来实现:

int MAX(int x,int y)
{return x>y ? x : y;
}

那这两种方法哪个更好呢?这就是我们接下来要讨论的问题了。

针对上述的例子,我更倾向使用宏。

原因有二:

  1. 用于调用函数和从函数返回得到代码可能比实际执行这个小型的计算工作所需要的时间更多(也就是创建函数栈帧需要时间)。所以宏比函数在程序的规模和速度方面更胜一筹
  2. 更为重要的是函数的参数必须要其声明特定的类型。所以函数只能在类型合适的表达式上使用。反之这个宏可以适用于整型、长整型、浮点型等可以用>来比较类型,也就是宏参数不需要声明类型,这是宏参数的绝对优势。

和函数相比宏的劣势

  1. 每次使用宏时,一份宏定义的代码插入到程序中。除非宏定义比较短,否则可能会大幅度提高程序的长度。
  2. 宏时无法调试的。因为它是处在预处理阶段的。
  3. 宏由于不需要规定参数类型,也就不够严谨。
  4. 宏可能会导致运算符优先级的问题,导致程序很容易出错。

宏有时候可以做到函数做不到的事情。比如:宏的参数可以出现各种类型,但是函数做不到。

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

7. #和##

7.1 #运算符

#运算符是将宏的一个参数转换为字符串字面量。它仅允许出现在带有参数的宏的替换列表中

#运算符所执行的操作可以理解为“字符串化”。

比如当我们有一个变量int a = 10;的时候,我们想打印出:the value of a is 10
我们就可以写成这样:

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

当我们按照下面的方法调用时,
PRINT(a);//当我们把a替换到宏的体内时,就会出现了#a,而#a就转换为了“a”的一个字符串。

7.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;\
}

使用宏来定义不同的函数:

GENERIC_MAX(int);
GENERIC_MAX(float);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;
}

8. 命名的约定

一般来讲函数和宏的使用语法很相似。所以仅凭借复发本身没有办法帮我们区分二者。

那平时我们的一个习惯是:

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

9. #undef (了解即可)

这条语句是用来移除一个宏定义。

#undef NAME
//如果现存的一个名字需要被重新定义,那么它的久名字首先被移除

10. 条件编译(重点)

我们先来聊一聊为什么需要条件编译?

在编译一个程序的时候我们如果要将一条指令(一组指令)编译或者放弃是很方便的。因为我们有条件编译。

比如说:

调试性代码,删除了可惜,保留又碍事,所以我们可以选择性的编译

#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;
}

常见的条件编译的指令:

1.
#if 常量表达式//...
#endif
如:
#define __DEBUG__ 1
#if __DEBUG__//...
#endif2.多个分支的条件编译
#if 常量表达式//...
#elif 常量表达式//...
#else//...
#endif3.判断是否被定义
#if defined(symbol)
#ifdef symbol //上面的简化#if !define(symbol)
#ifndef symbol4.嵌套条件编译指令
#if define(OS_UNIX)#ifdef OPTION1unix_version_option1();#endif#ifdef OPTION2unix_version_option2();#endif
#elif defined(OS_MSDOS)#ifdef OPTION2msdos_version_option2();#endif
#ednif

11. 头文件的包含

你是否还在问为什么得用“”来括起来自己写的头文件名,而不是像stdio.h那样的头文件用<>吗,本小节就来带大家解开谜语。

11.1 头文件被包含的方式:

11.1.1 本地文件包含

#include "filename.h"

查找策略:先在源文件所在的目录下查找,如果该头文件未找到,编译器就像查找函数库头文件一样在标准库位置查找头文件。
如果找不到则显示错误。

Linux环境的标准头文件路径:

/usr/include

Windows环境的标准头文件路径:

C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include
//这是VS2013的默认路径

注意:按照自己安装的路径来查找。

11.1.2 库文件的包含

#include<filename.h>

查找头文件是直接去到标准文件的路径下去查找,如果找不到就提示错误。

这样就是不是可以说,对于库文件也可以使用“”的形式包含?

答案是可以的,但是不推荐这么做。因为这样做查找的效率就会变低,当然这样也不容易区分包含的是本地文件还是库文件

至此,预处理详解的内容就全部完成了。如果觉得讲的还不错的话,麻烦给偶点个赞吧!!!
哈哈哈

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

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

相关文章

House of Rabbit

House of Rabbit 介绍&#xff1a; House of rabbit 是一种伪造堆块的技术&#xff0c;早在 2017 年已经提出&#xff0c;但在最近两个月才在 CTF 比赛中出现。我们一般运用在 fastbin attack 中&#xff0c;因为 unsorted bin 等其它的 bin 有更好的利用手段。 原理&#x…

接口基础知识6:详解http request body(一篇讲完常见请求体)

课程大纲 一、定义 HTTP请求体&#xff08;HTTP Request body&#xff09;&#xff1a;HTTP请求消息的可选部分&#xff0c;仅在请求方法支持且需要发送数据时使用。 POST方法、PUT方法有请求体&#xff0c;GET和HEAD方法没有请求体。 请求头和请求体之间会有一个空行&#…

【C++】面向对象三大特性之—— 继承 | 详解

目录 继承的概念 继承语法格式 继承方式 隐藏 继承下来的成员和父类是不是同一份 隐藏 基类和派生类对象赋值转换 继承中的作用域 派生类的默认成员函数 构造 拷贝构造 赋值重载 析构 继承与友元 继承与静态成员 菱形继承及菱形虚拟继承 多继承 菱形继承 菱形…

探索Linux -- 冯诺依曼体系、初始操作系统、初始进程、fork函数

一、冯诺依曼体系结构 1、概念 冯诺依曼结构也称普林斯顿结构&#xff0c;是一种将程序指令存储器和数据存储器合并在一起的存储器结构。 最早的计算机器仅内含固定用途的程序。若想要改变此机器的程序&#xff0c;就必须更改线路、更改结构甚至重新设计此机器。当然最早的计…

三防平板满足多样化定制为工业领域打造硬件解决方案

在当今工业领域&#xff0c;数字化、智能化的发展趋势日益显著&#xff0c;对于高效、可靠且适应各种复杂环境的硬件设备需求不断增长。三防平板作为一种具有坚固耐用、防水防尘防摔特性的工业级设备&#xff0c;正以其出色的性能和多样化的定制能力&#xff0c;为不同行业的应…

8.7 Day15 匿名用户访问FTP与日志查看

查看配置文件 vsftpd是一个认证文件&#xff0c;意味着ftp是通过vsftpd这个认证文件来对我们输入的用户名和密码进行认证的&#xff0c;那么这个认证文件在哪里呢&#xff1f; 所在位置如下&#xff1a; 查看文件配置内容 默认通过系统来验证&#xff0c;但现在我们欲做一个类…

Flink-DataWorks第二部分:数据集成(第58天)

系列文章目录 数据集成 2.1 概述 2.1.1 离线&#xff08;批量&#xff09;同步简介 2.1.2 实时同步简介 2.1.3 全增量同步任务简介 2.2 支持的数据源及同步方案 2.3 创建和管理数据源 文章目录 系列文章目录前言2. 数据集成2.1 概述2.1.1 离线&#xff08;批量&#xff09;同步…

VulnHub靶场-VulnOS:2

1.环境准备 下载地址&#xff1a;VulnOS: 2 ~ VulnHub 前言&#xff1a;由于我们下载的靶场是vdi文件&#xff0c;而我使用的是虚拟机&#xff0c;我们需要安装VirtualBox将vdi文件转换成虚拟机的vmdk文件vdi转vmdk VirtualBox与VMware硬盘格式转换及使用方法-CSDN博客 虚拟…

【中等】 猿人学web第一届 第2题 js混淆 动态cookie 1

目录 调试干扰Hook Function 加密参数定位hook Cookie AST 解混淆字符串解密还原解密函数AST 配合解密函数还原字符串 ASCII 编码字符串还原字符串相加花指令(对象)剔除无用代码虚假 if剔除无引用代码剔除无引用的对象数值还原 switch 还原完整的 AST 代码代码注意 还原加密 请…

pygame小游戏

代码存在一些bug&#xff0c;感兴趣可自行修改&#xff0c;游戏运行后玩法与吃金币游戏类似。&#xff08;代码及结果比较粗糙&#xff0c;仅供参考&#xff09; 注&#xff1a;&#xff08;图片、音乐、音效文件老是上传上传不上&#xff0c;想要可私&#xff0c;也可以自己找…

如何在银河麒麟操作系统上搭建 Electron (含 Electron 打包指南)

本次教程所用版本 Eletron版本&#xff1a;31.3.1 Electron-packager版本&#xff1a;17.1.2 VScode版本&#xff1a;1.92.0 Node版本&#xff1a;18.19.0 npm版本&#xff1a;10.2.3 前言&#xff1a; 随着跨平台应用开发的需求日益增长&#xff0c;Electron 和 Qt 成为…

Midjourney入门-提示词基础撰写与公式

​ 前言 在前几篇教程里我们已经可以初步使用Midjourney进行出图了。 包括也了解了Midjourney的指令与参数。 但如果你想用Midjourney去生成各种各样高质量的图片&#xff0c; 并且生成的图片是你想要的画面内容&#xff0c;也就是更好控制生成图片的画面内容与风格&#xf…

书生大模型实战营闯关记录----第八关:书生大模型全链路开源开放体系

书生大模型全链路开源开放体系 一、概述 书生大模型&#xff0c;即InternLM系列模型&#xff0c;是由上海人工智能实验室书生团队开发的一系列大语言模型。这些模型以其强大的功能而著称&#xff0c;涵盖了从基础的语言理解到复杂的数学解题和图文创作等多个领域。 发展历程…

【每日面经】快手面经

ConcurrentHashMap和HashMap的区别&#xff1f;使用场景&#xff1f; 线程安全性 concurrentHashMap是线程安全的&#xff0c;HashMap不是线程安全的锁机制 ConcurrentHashMap采用的是分段锁&#xff08;Sagment&#xff09;机制&#xff0c;降低所得粒度提高了并发性能 Curr…

4章4节:临床数据科学中如何用R来进行缺失值的处理

在临床科研中,由于失访、无应答或记录不清等各种原因,经常会遇到数据缺失的问题。本文将深入探讨医学科研中数据缺失的成因、分类、影响以及应对方法,结合R语言的实际应用,为医学研究人员提供全面的解决方案。 一、认识缺失数据 其实,很多医学的纵向研究因获取数据资料时…

38.【C语言】指针(重难点)(C)

目录: 8.const 修饰指针 *修饰普通变量 *修饰指针变量 9.指针运算 *指针或-整数 *指针-指针 *指针关系运算 往期推荐 承接上篇37.【C语言】指针&#xff08;重难点&#xff09;&#xff08;B&#xff09; 8.const 修饰指针 const 全称 constant adj.不变的 *修饰普通变量 #…

java.lang.NoClassDefFoundError: ch/qos/logback/core/util/StatusPrinter2

1、问题 SpringBoot升级报错&#xff1a; Exception in thread "main" java.lang.NoClassDefFoundError: ch/qos/logback/core/util/StatusPrinter2 类找不到&#xff1a; Caused by: java.lang.ClassNotFoundException: ch.qos.logback.core.util.StatusPrinter22、…

HDFS写入数据的流程图

1.客户端向namenode发送请求&#xff0c;请示写入数据 2.namenode接受请求后&#xff0c;判断这个用户是否有写入权限&#xff0c;如果不具备直接报错&#xff1b;如果有写入权限&#xff0c;接着判断在要写入的目录下是否已经存在这个文件&#xff0c;如果存在&#xff0c;直…

PHP语言特性漏洞汇总【万字详解】

文章目录 任意文件下载PHP弱类型比较字符比较绕过代码示例过程 SHA1比较绕过MD5比较绕过SESSION比较绕过STRCMP比较绕过科学计算法绕过概念复现复现2 json_decode&#xff08;&#xff09;绕过概念源码分析 ereg绕过概念复现复现2 array_search强相等绕过概念复现 文件包含生成…

螺旋矩阵 | LeetCode-59 | LeetCode-54 | 分类讨论

&#x1f64b;大家好&#xff01;我是毛毛张! &#x1f308;个人首页&#xff1a; 神马都会亿点点的毛毛张 &#x1f383;分类不好&#xff0c;这道题就做不出来&#xff01;&#x1f388; &#x1f4cc;LeetCode链接&#xff1a;59. 螺旋矩阵 II &#x1f4cc;LeetCode链接…