C语言学习第二十四天(预处理)

1、预处理符号

C语言设置了一些可以直接使用的预处理符号

__FILE__//进行编译的源文件
__LINE__//文件当前的行号
__DATE__//文件被编译的日期
__TIME__//文件被编译的时间
__STOC__//如果编译器遵循ANSI C 其值是1,否则未定义

一个例子:
 

printf("file:%s line:%d\n",__FILE__,__LINE__);

2、#define定义常量

#define name stuff

举个例子

#define MAX 1000
#define reg register //为register这个关键字创建一个简短的名字
#define do_forever for(;;)
#define CASE break;case //这样可以在写case语句的时候自动补上break
//如果定义的stuff过长,可以分成几行写,除了最后一行外,每一行的后面都要加一个反斜杠(续写序)
#define DEBUG_PRINT printf("file:%s\tline:%d\t \date:%s\ttime:%s\n",\__FILE__,__LINE__,     \__DATE__,__TIME__)

并且,需要注意的是,在define定义标识符的时候,最好不要在最后加上  ; 

否则容易导致错误

3、#define定义宏

#define 机制还有一个规定,允许把参数替换到文本当中,这种实现通常称为宏或者是定义宏

下面是宏的声明方式:

#define name(parament-list) stuff

其中的parament-list是一个有逗号隔开的符号表,他们可能出现在stuff当中

需要特别注意的是:参数列表的左括号必须与name紧邻,如果两者之间有任何的空白字符,参数列表就会被解释为stuff的一部分

一个例子:

#define SQUARE(x) x*x

这个宏接受一个参数x。如果在上述声明之后,把SQUARE(5)置于程序当中,预处理器就会用下面这个表达式替换下面的表达式 5*5

这个宏还是有一定的问题的,请看下面的代码:

int a = 5;
printf("%d\n",SQUARE(a+1));

我们感觉,这个代码的最终结果是36,实则不然,运行出来的结果是11

其实这个代码可以等效为:

printf("%d\n",a+1*a+1);

所以这个宏定义需要加上小括号

#define SQUARE(x) (x)*(x)

4、带有副作用的宏参数

当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,在使用宏的时候就可能出现危险。副作用就是表达式求值的时候出现的永久性效果

x+1;//不带副作用
x++;//带有副作用

5、宏替换的规则

1、在调用宏的时候,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,他们首先被替换

2、替换文本随着被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换

3、最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述过程。

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

6、宏函数的对比

比如想在两个数当中找到较大的一个的时候,可以这样写:

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

不使用函数完成这个任务的原因:

1、用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作的时间更多。

2、函数的参数声明一定是要特定的类型,所以函数只能在类型合适的表达式上使用。反之这个宏可以用于各种变量。宏是类型无关的

但是这个宏也有自己的缺点:

1、每次使用宏的时候,一份宏定义的代码插入到程序当中。除非宏比较短,不然的话会大幅度增加程序的长度

2、使用宏是无法调试的

3、宏是类型无关的,也就不够严谨

4、宏可能导致运算符优先级的问题,导致程序容易出错

宏还有一个优点:宏的参数可以出现类型,函数却做不到这一点

#define MALLOC(num,type)\(type )malloc(num sizeof(type))//使用一下
MALLOC(10,int);
//=>相当于是(int )malloc(10,sizeof(int));  

7、#和##

#运算符

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

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

当我们有一个变量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”,这个字符串代码就会被解析为:

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

打印出来就是:

the value of a is 10

##运算符

##可以把位于它两边的符号合成一个符号,它允许宏定义从分离的文本片段创建标识符

这样的链接必须产生一个合法的标识符。否则其结果就是未定义的

举个例子:

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)  //替换到宏体内后int##max生成了新的符号 int_max作为函数名
GENERIC_MAX(float)//替换到宏体内后float##max生成了新的符号 float_max作为函数名

8、命名的约定

把宏名全部大写

函数名不要全部大写

9、#undef

这条指令用于移除一个宏定义

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

10、命令行定义

许多C 的编译器提供了⼀种能⼒,允许在命令⾏中定义符号。⽤于启动编译过程。

当我们根据同⼀个源⽂件要编译出⼀个程序的不同版本的时候,这个特性有点⽤处。(假定某 个程序中声明了⼀个某个⻓度的数组,如果机器内存有限,我们需要⼀个很⼩的数组,但是另外⼀个 机器内存⼤些,我们需要⼀个数组能够⼤些。

#include <stdio.h>
int main()
{int array [ARRAY_SIZE];int i = 0;for(i = 0; i< ARRAY_SIZE; i ++){array[i] = i;}for(i = 0; i< ARRAY_SIZE; i ++){printf("%d " ,array[i]);}printf("\n" );return 0;
}
//linux 环境演⽰
gcc -D ARRAY_SIZE=10 programe.c

11、条件编译

选择性编译使调试性的代码是否参与编译,举个例子:

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

下面是常见的条件编译指令:

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

为了避免头⽂件的重复引⼊。可以使用条件编译

#ifndef __TEST_H__
#define __TEST_H__
//头⽂件的内容
#endif //__TEST_H__

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

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

相关文章

JNDI注入Log4jFastJson白盒审计不回显处理

目录 0x00 前言 0x01 Maven 仓库及配置 0x02 JNDI 注入简介 0x03 Java-第三方组件-Log4J&JNDI 0x04 Java-第三方组件-FastJson&反射 0x05 白盒审计 - FastJson 0x06 白盒审计 - Log4j 0x07 不回显的处理方法 0x00 前言 希望和各位大佬一起学习&#xff0c;如果…

多线程面试题

文章目录 1. 如何停止正在运行的线程2. 请你谈谈JMM&#xff08;java内存模型&#xff09;3. AQS4. ReentrantLock实现原理5. 死锁怎么检测 1. 如何停止正在运行的线程 设置一个共享变量作为线程退出的标记&#xff0c;当这个标记不满足时while循环&#xff0c;线程一直运行&a…

uniapp图片上传说明

目录 1.文件上传组件 2.单文件上传 3.多文件上传 4.注意点 1.文件上传组件 前端上传组件使用uni-file-picker&#xff0c;可以自行进行下载使用。默认上传到绑定的服务空间&#xff0c;配置属性auto-upload为false关闭自动上传&#xff0c;可以限定上传的是图片还是文件&am…

Databend 开源周报第 124 期

Databend 是一款现代云数仓。专为弹性和高效设计&#xff0c;为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务&#xff1a;https://app.databend.cn 。 Whats On In Databend 探索 Databend 本周新进展&#xff0c;遇到更贴近你心意的 Databend 。 新增对 Delta 和…

使用Python编写简单网络爬虫实例:爬取图片

&#x1f34e;个人主页 &#x1f3c6;个人专栏&#xff1a;日常聊聊 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 ​编辑 简介 步骤 1. 安装依赖库 2. 创建目录 3. 发送HTTP请求并解析页面 4. 查找图片标签并下载图片 注意事项 结语 我的其他博客 简介 网络爬虫是一种…

等保测评主要保护哪些方面的安全?

等保测评是经公安部认证的具有资质的测评机构&#xff0c;依据国家信息安全等级保护规范规定&#xff0c;受有关单位委托&#xff0c;按照有关管理规范和技术标准&#xff0c;对信息系统安全等级保护状况进行检测评估的活动。那么企业做等保“保”的是什么呢&#xff1f; 等保主…

【js文件】谷歌地图 markerclusterer.js

谷歌地图,点聚合,所使用的js function MarkerClusterer(map, opt_markers, opt_options) {this.extend(MarkerClusterer, google.maps.OverlayView);this.map_ map;/*** type {Array.<google.maps.Marker>}* private*/this.markers_ [];/*** type {Array.<Cluster&…

(自适应手机版)全屏滚动装修装潢公司网站模板

(自适应手机版)全屏滚动装修装潢公司网站模板 PbootCMS内核开发的网站模板&#xff0c;该模板适用于装修公司网站、装潢公司网站类等企业&#xff0c;当然其他行业也可以做&#xff0c;只需要把文字图片换成其他行业的即可&#xff1b; 自适应手机版&#xff0c;同一个后台&a…

SQL Server 安装教程

安装数据库 1、启动SQL Server2014安装程序&#xff0c;运行setup.exe文件&#xff0c;打开”SQL Server安装中心“对话框&#xff0c;单击左侧 的导航区域中的”安装“选项卡。 2、选择”全新SQL Server独立安装或向现有安装添加功能“&#xff0c;启动SQL Server2014安装向导…

自动驾驶技术入门平台分享:百度Apollo开放平台9.0全方位升级

目录 平台全方位的升级 全新的架构 工具服务 应用软件&#xff08;场景应用&#xff09; 软件核心 硬件设备 更强的算法能力 9.0版本算法升级总结 更易用的工程框架 Apollo开放平台9.0版本的技术升级为开发者提供了许多显著的好处&#xff0c;特别是对于深度开发需求…

.gitignore和git lfs学习

The ninth day——12.18 1. .gitignore 忽略规则优先级 从命令行中读取可用的忽略规则当前目录定义的规则父级目录定义的规则&#xff0c;依次递推$GIT_DIR/info/exclude 文件中定义的规则core.excludesfile中定义的全局规则 忽略规则匹配语法 空格不匹配任意文件&#xff…

LVS+Keepalived 高可用集群

一.Keepalived工具介绍 1.支持故障自动切换(Failover) 2.支持节点健康状态检查(Health Checking) 3.基于vrrp协议完成地址流动 4.为vip地址所在的节点生成ipvs规则(在配置文件中预先定义) 5.为ipvs集群的各RS做健康状态检测 6.基于脚本调用接口完成脚本中定义的功能&…

MyBatis ${}和#{}区别

sql防注入底层jdbc类型转换当简单类型参数$不防止Statment不转换value#防止preparedStatement转换任意 除模糊匹配外&#xff0c;杜绝使用${} MyBatis教程&#xff0c;大家可以借鉴 MyBatis 教程_w3cschoolMyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。…

RPC(5):AJAX跨域请求处理

接上一篇RPC&#xff08;4&#xff09;&#xff1a;HttpClient实现RPC之POST请求进行修改。 1 修改客户端项目 1.1 修改maven文件 修改后配置文件如下&#xff1a; <dependencyManagement><dependencies><dependency><groupId>org.springframework.b…

数据智慧:如何利用可视化提升效率

数据可视化是一项强大的工具&#xff0c;能够显著提高工作效率和决策的准确性。下面我就以可视化从业者的角度&#xff0c;简单谈谈数据可视化是如何助力效率提升的。 直观理解复杂数据 数据可视化将抽象的数据转化为图表、图形或仪表盘&#xff0c;使数据更易于理解。这种直观…

openstack-keystone服务

文章目录 keystone服务安装和配置先决条件安装并配置组件运行以下命令来安装包。编辑文件 /etc/keystone/keystone.conf 并完成如下动作&#xff1a;初始化身份认证服务的数据库&#xff1a;初始化Fernet keys&#xff1a;Bootstrap the Identity service: 配置 Apache HTTP 服…

【算法题】1. 两数之和

目录 题目 题解 题目 给定一个整数数组nums和一个整数目标值target&#xff0c;请你在该数组中找出和为目标值target的那两个整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现。 你可以…

Linux系统之部署Linux管理面板1Panel

一、介绍 1.1简介 1Panel 是一个现代化、开源的 Linux 服务器运维管理面板。 1.2特点 快速建站&#xff1a;深度集成 Wordpress 和 Halo&#xff0c;域名绑定、SSL 证书配置等一键搞定&#xff1b; 高效管理&#xff1a;通过 Web 端轻松管理 Linux 服务器&#xff0c;包括应用管…

AWS S3相关配置笔记

关闭 阻止所有公开访问 存储桶策略(开放外部访问) {"Version": "2012-10-17","Id": "S3PolicyId1","Statement": [{"Sid": "statement1","Effect": "Allow","Principal"…

[最后一个月征稿、ACM独立出版】第三届密码学、网络安全和通信技术国际会议(CNSCT 2024)

第三届密码学、网络安全和通信技术国际会议&#xff08;CNSCT 2024&#xff09; 2024 3rd International Conference on Cryptography, Network Security and Communication Technology 一、大会简介 随着互联网和网络应用的不断发展&#xff0c;网络安全在计算机科学中的地…