当前位置: 首页 > news >正文

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,符合题目要求。如果输入其他年份,程序也能正确判断并输出相应的结果。

相关文章:

C语言之预处理

目录 前言 宏定义define的用法 文件包含include的用法 条件编译的用法 其他预处理命令 练习题 练习一 练习二 练习三 前言 预处理命令可以改变程序设计环境&#xff0c;提高编程效率&#xff0c;它们并不是C语言本身的组成部分&#xff0c;不能直接对它们进行编译&am…...

css步骤条

html 代码以及样式 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>css步骤条</title><style>.steps {display: flex;justify-content: space-between;padding: 0;margin: 20px 10px;lis…...

[Hive] 常见函数

文章目录 字符串函数数值函数随机函数日期和时间函数字符串转时间 聚合函数数组函数结构体函数数组函数映射函数 map正则处理JSON 字符串函数 CONCAT(string1, string2, …)&#xff1a;将多个字符串连接成一个字符串。 LENGTH(string)&#xff1a;返回字符串的长度。 LOWER…...

Mac用NTFS文件夹读写NTFS硬盘 NTFS能复制多大的文件

Mac作为一款备受欢迎的计算机操作系统&#xff0c;具备了许多令人惊叹的功能和特性。然而&#xff0c;对于一些Mac用户来说&#xff0c;使用NTFS格式的硬盘可能存在一些疑问。他们可能想知道Mac是否能够读写NTFS格式的硬盘&#xff0c;以及NTFS格式的硬盘是否有文件大小的限制。…...

【unity3D】Scroll Rect组件—制作下滑列表

&#x1f497; 未来的游戏开发程序媛&#xff0c;现在的努力学习菜鸡 &#x1f4a6;本专栏是我关于游戏开发的学习笔记 &#x1f236;本篇是unity的Scroll Rect组件 Scroll Rect组件 基础知识详细说明案例演示——制作一个简单的下滑框扩展 介绍&#xff1a;Scroll Rect组件是用…...

网络扫描与网络监听

前言&#xff1a;前文给大家介绍了网络安全相关方面的基础知识体系&#xff0c;以及什么是黑客&#xff0c;本篇文章笔者就给大家带来“黑客攻击五部曲”中的网络扫描和网络监听 目录 黑客攻击五部曲 网络扫描 按扫描策略分类 按照扫描方式分类 被动式策略 系统用户扫描 …...

Codeforces Round 904 (Div. 2) C

C. Medium Design 思路&#xff1a;我们设最大值所在的下标为 x x x,最小值所在的下标为 y y y,那么我们考虑一段区间对于答案的贡献&#xff1a; 若一段区间覆盖了 x x x&#xff0c;但没有覆盖 y y y,那么这段区间需要选择 若一段区间覆盖了 y y y&#xff0c;但没有覆盖 x…...

DBeaver连接数据库报错:Public Key Retrieval is not allowed 的解决方案

写在前面&#xff1a; DBeaver是一款免费的数据库管理工具&#xff0c;安装也是傻瓜式一键安装&#xff0c;比较推荐。 DBeaver官网&#xff08;加载有点慢&#xff0c;耐心等待&#xff09;&#xff1a;DBeaver Community | Free Universal Database Tool 报错详情&#xff…...

DeepFace【部署 04】轻量级人脸识别和面部属性分析框架deepface使用Docker部署CPU+GPU两个版本及cuDNN安装

使用Docker部署CPUGPU 1.CPU2.GPU3.cuDNN安装3.1 Prerequisites3.2 下载Linux版本cuDNN3.3 安装 1.CPU 本说明基于DeepFace的Docker镜像文件deepface_image.tar进行说明。 # 1.导入镜像 docker load -i deepface_image.tar# 2.创建模型文件夹【并将下载好的模型文件上传】 mk…...

程序生活 - 减肥小记

文章目录 缘起健康就好了吗&#xff1f;关于外在和物质生活难与易 我的减肥生活一些细节轻断食戒糖、油炸、重口味睡眠改变社交方式用运动化解压力不喝牛奶 缘起 2017年的一次腿受伤&#xff0c;让我从一个怎么都吃不胖的人&#xff0c;变成了一个实实在在的胖子。 如果你从来…...

深度学习_4_实战_直线最优解

梯度 实战 代码&#xff1a; # %matplotlib inline import random import torch import matplotlib.pyplot as plt # from d21 import torch as d21def synthetic_data(w, b, num_examples):"""生成 Y XW b 噪声。"""X torch.normal(0,…...

《视觉SLAM十四讲》公式推导(三)

文章目录 CH3-8 证明旋转后的四元数虚部为零&#xff0c;实部为罗德里格斯公式结果 CH4 李群与李代数CH4-1 SO(3) 上的指数映射CH4-2 SE(3) 上的指数映射CH4-3 李代数求导对极几何&#xff1a;本质矩阵奇异值分解矩阵内积和迹 CH3-8 证明旋转后的四元数虚部为零&#xff0c;实部…...

pnpm、npm、yarn的区别

pnpm、npm、yarn是三种不同的包管理器&#xff0c;它们之间有一些区别。 安装速度&#xff1a;pnpm的安装速度比npm和yarn快&#xff0c;因为它使用了只下载必需的模块&#xff0c;而不是下载整个依赖树。此外&#xff0c;pnpm还可以并行下载模块&#xff0c;从而进一步提高下…...

搞定蓝牙——第四章(GATT协议)

搞定蓝牙——第四章&#xff08;GATT协议&#xff09; 原理介绍层次结构server和client端Attribute ESP32代码 文章下面用的英文表示&#xff1a; server和client&#xff1a;服务端和客户端 char.&#xff1a;characteristic缩写&#xff0c;特征 Attribute:属性 ATT:Attribut…...

Go语言入门心法(十四): Go操作Redis实战

Go语言入门心法(一): 基础语法 Go语言入门心法(二): 结构体 Go语言入门心法(三): 接口 Go语言入门心法(四): 异常体系 Go语言入门心法(五): 函数 Go语言入门心法(六): HTTP面向客户端|服务端编程 Go语言入门心法(七): 并发与通道 Go语言入门心法(八): mysql驱动安装报错o…...

Java学习笔记(三)

前言 这个主要就是想记录一个点&#xff0c;就是二维数组保存的元素就是一维数组的地址&#xff0c;这个概念大家都知道了&#xff0c;那么接下来就是我最近写程序发生的一个事情了。 随机打乱一个一维数组 这个程序我相信大家都是会写的&#xff0c;通过randomArr来随机打乱…...

Flutter笔记:GetX模块中不使用 Get.put 怎么办

Flutter笔记 GetX模块中不使用 Get.put 怎么办 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/13400672…...

2023前端面试整理

1. 介绍一下最近参与的项目,负责那些业务,在开发过程中遇到过问题吗&#xff1f;最后是咋样处理的&#xff1f; 之前负责过大小十几个项目&#xff0c;负责过浙里办的整套上架流程&#xff0c;负责过数据大屏统计&#xff0c;后台管理系统文书生成表单生成等&#xff0c;浙政钉…...

文化融合:TikTok如何弥合跨文化差异

随着全球化的加速和数字媒体的崛起&#xff0c;社交媒体平台已经成为连接世界各地人们的纽带。其中&#xff0c;TikTok作为一个引领者&#xff0c;正在以惊人的速度消除跨文化差异&#xff0c;促进文化融合&#xff0c;使人们更加了解和尊重不同背景和传统。 本文将深入探讨Ti…...

asp.net core获取config和env

配置文件的读取和使用 //读取配置文件直接使用 var configModel configuration.GetSection("DataBaseConfig").Get<DataBaseConfigModel>(); //读取配置文件注入到IOC中 services.Configure<AssemblyConfig>(configuration.GetSection("AssemblyC…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)

说明&#xff1a; 想象一下&#xff0c;你正在用eNSP搭建一个虚拟的网络世界&#xff0c;里面有虚拟的路由器、交换机、电脑&#xff08;PC&#xff09;等等。这些设备都在你的电脑里面“运行”&#xff0c;它们之间可以互相通信&#xff0c;就像一个封闭的小王国。 但是&#…...

(十)学生端搭建

本次旨在将之前的已完成的部分功能进行拼装到学生端&#xff0c;同时完善学生端的构建。本次工作主要包括&#xff1a; 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

工业安全零事故的智能守护者:一体化AI智能安防平台

前言&#xff1a; 通过AI视觉技术&#xff0c;为船厂提供全面的安全监控解决方案&#xff0c;涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面&#xff0c;能够实现对应负责人反馈机制&#xff0c;并最终实现数据的统计报表。提升船厂…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

React Native在HarmonyOS 5.0阅读类应用开发中的实践

一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强&#xff0c;React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 &#xff08;1&#xff09;使用React Native…...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

DBAPI如何优雅的获取单条数据

API如何优雅的获取单条数据 案例一 对于查询类API&#xff0c;查询的是单条数据&#xff0c;比如根据主键ID查询用户信息&#xff0c;sql如下&#xff1a; select id, name, age from user where id #{id}API默认返回的数据格式是多条的&#xff0c;如下&#xff1a; {&qu…...

前端开发面试题总结-JavaScript篇(一)

文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包&#xff08;Closure&#xff09;&#xff1f;闭包有什么应用场景和潜在问题&#xff1f;2.解释 JavaScript 的作用域链&#xff08;Scope Chain&#xff09; 二、原型与继承3.原型链是什么&#xff1f;如何实现继承&a…...

ArcGIS Pro制作水平横向图例+多级标注

今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作&#xff1a;ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等&#xff08;ArcGIS出图图例8大技巧&#xff09;&#xff0c;那这次我们看看ArcGIS Pro如何更加快捷的操作。…...