C语言之预处理

目录

前言

宏定义define的用法

文件包含include的用法

条件编译的用法

其他预处理命令

练习题

练习一

练习二

练习三


前言

预处理命令可以改变程序设计环境,提高编程效率,它们并不是C语言本身的组成部分,不能直接对它们进行编译,必须在对程序进行编译之前,先对程序中这些特殊的命令进行“预处理”。经过预处理后,程序就不再包括预处理命令了,最后再由编译程序对预处理之后的源程序进行编译处理,得到可供执行的目标代码。C语言提供的预处理功能有三种,分别为宏定义、文件包含和条件编译。

宏定义define的用法

在C语言中,#define是用于创建宏定义的预处理指令。宏定义是一种简单的文本替换机制,可以用来定义常量、函数或代码片段。它的基本语法如下:

#define 宏名 替换文本

其中,宏名是你给宏定义起的名称,替换文本是要替换的内容。

下面是一些常见的宏定义用法示例:

1、定义常量:

#define PI 3.14159

这里将宏名PI定义为常量值3.14159,后续使用PI时会被替换为3.14159。

2、定义带参数的宏:

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

这里定义了一个带参数的宏SQUARE,用于计算一个数的平方。当使用SQUARE(5)时,宏展开后会变成((5) * (5)),即25。

3、定义条件编译:

#define DEBUG

 这里定义了一个宏DEBUG,用于开启调试模式。在代码中可以使用#ifdef和#endif来根据宏是否定义执行不同的代码块。

4、定义复杂的宏:

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

这里定义了一个宏MAX,用于返回两个数中的最大值。当使用MAX(10, 20)时,宏展开后会变成((10) > (20) ? (10) : (20)),即20。

需要注意的是,宏定义只是简单的文本替换,没有类型检查和作用域限制。因此,在使用宏定义时需要谨慎,避免出现意外的结果。

另外,为了增加代码的可读性和可维护性,通常建议在宏定义时加上括号,以避免优先级问题。例如,在上面的示例中,将宏定义改为#define SQUARE(x) ((x) * (x)),可以确保在宏展开时正确计算。

总结起来,#define是C语言中用于创建宏定义的预处理指令,可以用来定义常量、函数或代码片段。宏定义通过简单的文本替换机制,在编译前将宏名替换为对应的文本。合理使用宏定义可以提高代码的可读性和灵活性,但也需要注意避免潜在的问题。

文件包含include的用法

在C语言中,#include是用于包含头文件的预处理指令。头文件包含了函数声明、宏定义和类型定义等信息,可以被多个源文件共享使用。#include指令告诉编译器在编译时将指定的头文件内容插入到当前文件中。它的基本语法如下:

#include <头文件名>
或者
#include "头文件名"

其中,<头文件名>用于包含系统提供的标准头文件,而"头文件名"用于包含用户自定义的头文件。

下面是一些常见的#include用法示例:

1、包含标准库头文件:

#include <stdio.h>

这里使用#include <stdio.h>包含了标准库头文件stdio.h,该头文件中包含了输入输出相关的函数声明和常量定义。

2、包含自定义头文件:

#include "myheader.h"

 这里使用#include "myheader.h"包含了自定义的头文件myheader.h,该头文件中可以包含用户自定义的函数声明、宏定义和类型定义等。

需要注意的是,头文件通常包含在.h文件中,并且应该包含相应的函数声明和宏定义,而不是实际的函数实现。函数实现通常在对应的.c文件中。

另外,为了避免重复包含同一个头文件,可以使用条件编译指令#ifndef、#define和#endif来保护头文件内容。例如:

#ifndef MYHEADER_H
#define MYHEADER_H// 头文件内容...#endif

 这样可以确保头文件只被包含一次,避免重复定义和编译错误。

总结起来,#include是C语言中用于包含头文件的预处理指令,可以将头文件的内容插入到当前文件中。通过包含头文件,可以共享函数声明、宏定义和类型定义等信息,提高代码的重用性和可维护性。在使用#include时,需要注意选择正确的头文件,并遵循良好的编码规范。

条件编译的用法

在C语言中,条件编译是一种预处理指令,用于根据条件来选择性地编译代码块。条件编译可以根据宏的定义与否,决定是否编译某段代码。这对于在不同平台、不同编译选项下编写可移植的代码非常有用。

条件编译使用以下几个预处理指令:

1、#ifdef 和 #endif:

#ifdef 宏名// 被包含的代码块
#endif

如果宏宏名已经定义,则会编译#ifdef和#endif之间的代码块,否则会忽略这部分代码。

2、#ifndef 和 #endif:

#ifndef 宏名// 被包含的代码块
#endif

如果宏宏名没有定义,则会编译#ifndef和#endif之间的代码块,否则会忽略这部分代码。

3、#if、#elif、#else 和 #endif:

#if 表达式// 被包含的代码块
#elif 表达式// 被包含的代码块
#else// 被包含的代码块
#endif

根据表达式的真假情况,选择性地编译相应的代码块。只有满足条件的代码块会被编译,其他代码块会被忽略。

这些条件编译指令可以与宏定义结合使用,例如:

#define DEBUG#ifdef DEBUG// 调试模式下的代码
#else// 发布模式下的代码
#endif

在上述示例中,如果宏DEBUG已经定义,则会编译调试模式下的代码,否则会编译发布模式下的代码。

需要注意的是,条件编译是在预处理阶段进行的,与运行时逻辑无关。因此,条件编译指令不会影响程序运行时的行为。

另外,条件编译还可以用于根据不同平台或编译选项来选择性地包含不同的头文件。例如:

#ifdef _WIN32#include <windows.h>
#elif __linux__#include <unistd.h>
#endif

在上述示例中,根据不同的操作系统平台,选择性地包含了不同的头文件。

总结起来,条件编译是C语言中一种用于根据条件选择性编译代码块的预处理机制。通过使用#ifdef、#ifndef、#if、#elif、#else和#endif等条件编译指令,可以根据宏的定义与否、表达式的真假等情况来选择性地编译代码,提高代码的可移植性和灵活性。在使用条件编译时,需要注意合理选择条件,并遵循良好的编码规范。

其他预处理命令

除了上面介绍的之外,C语言还有#error、#line、#pragma等其他常用的预处理命令,在很多C语言的程序中也是经常可见的,下面简单介绍一下它们。

1、#undef:

#undef 宏名

取消一个已经定义的宏。例如,#undef PI 可以取消之前定义的PI宏。 

2、#pragma:

#pragma 指令名

使用指定的编译器指令。不同的编译器支持的指令可能不同,一些常见的指令包括#pragma once(保证头文件只被包含一次)、#pragma pack(n)(设定结构体的字节对齐方式)等。

3、#error:

#error 错误信息

在编译时输出指定的错误信息,并停止编译。例如,#error "Invalid input" 可以输出错误信息Invalid input并停止编译。 

4、#warning: 

#warning 警告信息

在编译时输出指定的警告信息,但不会停止编译。例如,#warning "Unused variable" 可以输出警告信息Unused variable。

需要注意的是,预处理指令是在编译前由预处理器处理的,它们不是C语言的语句,也不会被编译成机器码。因此,在使用预处理指令时,需要注意遵循预处理器的语法规则,并且遵循良好的编码规范。

总结起来,C语言还提供了一些其他的预处理指令,包括#define、#undef、#include、#pragma、#error和#warning等。通过使用这些指令,可以在编译前对源代码进行预处理,提高代码的可读性、可维护性和可移植性。在使用预处理指令时,需要注意遵循预处理器的语法规则,并遵循良好的编码规范。

练习题

练习一

参考答案

#include <stdio.h>#define SWAP(a, b) do { \int temp = a; \a = b; \b = temp; \
} while(0)int main() {int num1, num2;scanf("%d %d", &num1, &num2);SWAP(num1, num2);printf("%d %d\n", num1, num2);return 0;
}

在上述代码中,我们定义了一个带参数的宏SWAP,它接受两个参数a和b。在宏展开时,我们使用一个临时变量temp来保存a的值,然后将b的值赋给a,最后将temp的值赋给b,实现了两个参数值的互换。

在main函数中,我们首先使用scanf函数从输入中读取两个数num1和num2。然后,我们调用宏SWAP,将num1和num2作为实参传递给宏,实现了两个数值的互换。最后,我们使用printf函数输出交换后的两个数num1和num2。

运行程序,输入示例中的1 2,即可得到输出结果2 1,符合题目要求。

练习二

参考答案

#include <stdio.h>
#include <math.h>#define CALCULATE_S(a, b, c) ((a + b + c) / 2.0)
#define CALCULATE_AREA(a, b, c) (sqrt(CALCULATE_S(a, b, c) * \(CALCULATE_S(a, b, c) - a) * \(CALCULATE_S(a, b, c) - b) * \(CALCULATE_S(a, b, c) - c)))int main() {double a, b, c;scanf("%lf %lf %lf", &a, &b, &c);double area = CALCULATE_AREA(a, b, c);printf("%.3lf\n", area);return 0;
}

在上述代码中,我们定义了两个带参数的宏CALCULATE_S和CALCULATE_AREA,分别用于计算三角形的半周长S和面积area。在宏展开时,我们使用括号将各个表达式括起来,避免运算优先级带来的错误。

在main函数中,我们首先使用scanf函数从输入中读取三角形的三条边a、b、c。然后,我们调用宏CALCULATE_AREA,将a、b、c作为实参传递给宏,计算出三角形的面积。最后,我们使用printf函数输出计算得到的面积area,并保留三位小数。

运行程序,输入示例中的3 4 5,即可得到输出结果6.000,符合题目要求。

练习三

参考答案

#include <stdio.h>#define LEAP_YEAR(y) ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0 ? "L" : "N")int main() {int year;scanf("%d", &year);printf("%s\n", LEAP_YEAR(year));return 0;
}

在上述代码中,我们定义了一个宏LEAP_YEAR,用于判断给定的年份是否为闰年。在宏展开时,我们使用条件运算符(三目运算符)来进行判断:如果年份能被4整除且不能被100整除,或者能被400整除,则返回字符串"L"表示是闰年,否则返回字符串"N"表示不是闰年。

在main函数中,我们首先使用scanf函数从输入中读取年份year。然后,我们调用宏LEAP_YEAR,将year作为实参传递给宏,根据返回的字符串结果输出相应的结果。最后,我们使用printf函数输出结果,并换行。

运行程序,输入示例中的2000,即可得到输出结果L,符合题目要求。如果输入其他年份,程序也能正确判断并输出相应的结果。

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

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

相关文章

redis高可用

文章目录 redis高可用概述哨兵模式原理配置流程使用缺点 cluster集群原理特征流程缺点故障转移故障检测故障转移 集群配置和管理主要命令搭建集群创建集群查看集群配置信息测试集群主从切换扩容缩容 redis高可用概述 1、高可用是分布式的概念。 Redis的高可用性是指在Redis集群…

springsecurity学习笔记-未完

目录 前言 一、概念 1.什么是springsecurity 2.对比shiro 二、开始项目 1.建立一个空项目&#xff0c;建立module&#xff0c;引入相关依赖 2.启动项目&#xff0c;访问项目 3.自定义密码 总结 前言 记录一下学习springsecurity的过程 开发环境&#xff1a;IDEA 一、概念 1.…

274. H 指数

文章目录 一、题目1、题目描述2、基础框架3、原题链接 二、解题报告1、思路分析1.1 方案一1.2 方案二 2、时间复杂度3、代码详解3.1 方案一3.2 方案二 三、本题小知识 一、题目 1、题目描述 给你一个整数数组 citations &#xff0c;其中 citations[i] 表示研究者的第 i 篇论…

vue3学习(十二)--- 自定义指令

文章目录 Vue3 directive的钩子函数在setup内定义局部指令生命周期钩子参数详解函数形式简写案例1 --- 自定义拖拽指令案例2 --- 图片懒加载指令 Vue3 directive的钩子函数 created 元素初始化的时候beforeMount 指令绑定到元素后调用 只调用一次mounted 元素插入父级dom调用b…

字符串和数组的常用方法

字符串 str.slice(1) 获取除一个字符以外 str.slice(0,1) 获取第一个字符 长度 length() 拼接 str.concat(str2) charAt(index)返回指定索引处的字符 indexOf(str)返回指定字符串在此字符串中第一次出现处的索引 compareTo(str2)比较两个字符串 equals()和equalsIgnoreCase() g…

解决提交到App Store时的ITMS-90478和ITMS-90062错误

解决提交到App Store时的ITMS-90478和ITMS-90062错误 目录 引言 正文 1. 什么是ITMS-90478和ITMS-90062错误&#xff1f; 2. 解决方法 2.1 确定当前的版本号和构建号 2.2 递增版本号和构建号 2.3 再次尝试提交应用 总结 参考资料 错误记录 摘要&#xff1a;本文为iOS…

11.Vue2-事件处理器的用法

题记 vue2事件处理器的用法 v-on <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>实例</title> <script src"https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script> </head>…

node(三)express框架

文章目录 1.express介绍2.express初体验3.express路由3.1什么是路由&#xff1f;3.2路由的使用 1.express介绍 是一个基于Node平台的极简、灵活的WEB应用开发框架&#xff0c;官网地址&#xff1a;https://www.expressjs.com.cn/ 简单来说&#xff0c;express是一个封装好的工…

鼎鑫鸿鄴引入“能源互联网+”理念 打造共赢

近年来&#xff0c;随着全球能源消耗的不断增长和环境问题的日益突出&#xff0c;清洁能源转型成为全球共同关注的话题。中国作为全球最大的能源消费国&#xff0c;也在积极推动能源结构的优化和清洁能源的发展。鼎鑫鸿鄴新能源科技有限公司在推动清洁能源转型方面制定了一系列…

北太天元安装教程 及使用方法

北太天元是面向科学计算与工程计算的国产通用型科学计算软件。提供科学计算、可视化、交互式程序设计&#xff0c;具备丰富的底层数学函数库&#xff0c;支持数值计算、数据分析、数据可视化、数据优化、算法开发等工作&#xff0c;并通过SDK与API接口&#xff0c;扩展支持各类…

Vite介绍及实现原理

Vite介绍及实现原理 一、Vite简介1.1、什么是Vite1.2 、Vite的主要特性1.3、 为什么要使用Vite 二、Vite的实现原理2.1、依赖处理2.2、静态资源加载2.3、vue文件缓存2.4、 js/ts处理 三、热更新原理四、vite基本使用4.1、安装4.2、搭建项目 一、Vite简介 1.1、什么是Vite Vite…

在 Android 上测试 Kotlin 数据流

文章目录 一 创建虚构数据提供方二 在测试中断言数据流发出测试期间持续收集 三 测试 StateFlow使用 stateIn 创建的 StateFlow 转自&#xff1a; https://developer.android.google.cn/kotlin/flow/test?hlzh-cn#producer 与数据流进行通信的单元或模块的测试方式取决于受测对…

算法通关村第十二关白银挑战——仅仅反转英文字母问题解析

大家好&#xff0c;我是怒码少年小码。 今天做道经典的字符串算法题目。 仅仅反转字母 LeetCode 917&#xff1a;给你一个字符串 s &#xff0c;根据下述规则反转字符串&#xff1a; 所有非英文字母保留在原有位置。所有英文字母&#xff08;小写或大写&#xff09;位置反转…

Tomcat运维以及优化

Tomcat常用运维命令 # 查看版本/opt/data/app/tomcat-9.0.82/bin/catalina.sh version## 启动 /opt/data/app/tomcat-9.0.82/bin/startup.sh # 停止 /opt/data/app/tomcat-9.0.82/bin/shutdown.sh调整JVM 参数 方式1 vim /opt/data/app/tomcat-9.0.82/bin/catalina.sh # OS…

硬件加速绘制基础知识

目录 前置知识&#xff1a; OPENGL 和OPENGL ELS的关系 EGLSurface和EGLContext关系 上下文保存着状态集&#xff0c;什么是状态集&#xff1f; Thread和EGLSurface&#xff0c;EGLContext关系 具体api Display和EGL关系 Surface和EGLSurface的关系 大致初始化流程 绘…

以技术创新“谋局”,洗碗机市场的风向变了

在知乎、小红书等知识社区上&#xff0c;时常可以看到一些有趣的“种草”帖&#xff1a;扫地机器人和洗碗机&#xff0c;被并称为“解放人类双手的家电产品”。 特别是洗碗机的话题下&#xff0c;不少对清洁、节能、烘干、容量等卖点进行详尽阐述的科普文章&#xff0c;动辄就…

计算机网络——理论知识总结(上)

开新番&#xff0c;因为博主备考的学校计网只考察1/6的分值&#xff0c;而且定位偏向于送分题&#xff0c;因此在备考时并没有很高强度的复习。本帖基于王道考研的教辅总结归纳&#xff0c;虽然是408的教材&#xff0c;但忽略其中有难度的部分&#xff0c;如计算题、画图题等&a…

如何通过员工工时管理降低企业成本?

作为当今快节奏商业环境的领导者或管理者&#xff0c;掌握员工的工作时间对于控制企业成本和确保每个人都各尽其责至关重要。 员工工时表软件就是这样一款工时跟踪管理解决方案&#xff1a;数字化的工时表有助于保护企业的财务不会被无节制的开支冲垮。然而&#xff0c;引入此…

【信创】银河麒麟V10 安装postgis

安装postGis步骤 1、安装 proj4 #tar -zxvf proj-4.8.0.tar.gz #cd proj-4.8.0 #mkdir -p /opt/proj-4.8.0 #./configure --prefix=/opt/proj-4.8.0 #make && make install #vi /etc/ld.so.conf.d/proj-4.8.0.conf #ldconfig 2、安装 geos #tar -xjf geos-3.6.1.tar.b…

Spark SQL概述与基本操作

目录 一、Spark SQL概述 &#xff08;1&#xff09;概念 &#xff08;2&#xff09;特点 &#xff08;3&#xff09;Spark SQL与Hive异同 &#xff08;4&#xff09;Spark的数据抽象 二、Spark Session对象执行环境构建 (1)Spark Session对象 &#xff08;2&#xff09;代码演…