【C】预处理指令 #define, #include, #if...#elif...#else...#endif

目录

    • C 预处理
      • 1 #define
        • 1)基本语法
        • 2)常量宏
        • 3)表达式宏
        • 4)语句宏
        • 5)代码块宏
        • 6)总结
      • 2 #include
        • 1)基本语法
        • 2)头文件的作用
        • 3)头文件的保护
        • 4)示例
        • 5)头文件设计原则
      • 3 #if、#ifdef、ifndef、#elif、#else、#endif
        • 1)`#if` 指令
        • 2)`#ifdef` 和 `#ifndef` 指令
        • 3)`#elif` 指令
        • 4)`#else` 指令
        • 5)`#endif` 指令

C 预处理

预处理是C语言编译过程的第一个阶段,它主要由预处理器(Preprocessor)完成。

预处理指令#符号开头,不是C语句,是在编译之前由预处理器处理的命令。

常用预处理指令:#define, #include, #if…#elif…#else…#endif等

1 #define

#define 是C语言预处理器提供的指令,用于定义宏

宏是一种简单的文本替换机制,在编译前将源代码中的宏名替换为对应的宏值或代码片段。

1)基本语法
#define 宏名 替换文本

宏名: 通常是一个标识符,命名规则与变量相同。

替换文本: 可以是常量表达式语句代码块,用于替换宏名。

2)常量宏
#define PI 3.14159

这是最简单的宏定义,将 PI 定义为一个常量,所有出现 PI 的地方都会被替换为 3.14159

3)表达式宏
#define SQUARE(x) ((x) * (x))int result = SQUARE(5);  // 编译时会被替换为 int result = ((5) * (5));

这个宏用于计算传入参数的平方,是一个带有表达式的宏。

4)语句宏
#define PRINT_MESSAGE() printf("Hello, World!\n")PRINT_MESSAGE();  // 编译时会被替换为 printf("Hello, World!\n");

这个宏定义了一个打印消息的语句,可以在代码中使用 PRINT_MESSAGE() 来替代实际的 printf 语句。

5)代码块宏
#define MAX(a, b) \({ \typeof(a) _a = (a); \typeof(b) _b = (b); \_a > _b ? _a : _b; \})int max_value = MAX(10, 20);  // 编译时会被替换为 int max_value = ({ typeof(10) _a = (10); typeof(20) _b = (20); _a > _b ? _a : _b; });

这是一个用于获取两个数中较大值的宏,使用了代码块,其中包含了局部变量的定义和比较操作。

6)总结

宏虽然有其用处,但在实际编程中应慎重使用,确保宏的使用不会导致代码可读性下降或产生难以维护的问题。

在实际编程中,尽量使用函数代替宏,以提高代码的可读性和维护性。

2 #include

#include 是C语言预处理器指令之一,用于包含外部文件的内容。

1)基本语法
#include <header_file.h>
#include "header_file.h"
  • 尖括号 <>: 用于包含系统提供的头文件,通常是标准C库的头文件。

  • 双引号 "": 用于包含用户自定义的头文件,通常是项目内部的头文件。

  • 当使用尖括号 <> 时,编译器通常会在系统的标准头文件目录中搜索头文件。

  • 当使用双引号 "" 时,编译器会先在当前源代码文件所在的目录搜索,然后在系统的标准头文件目录中搜索。

2)头文件的作用

头文件是C语言中一种用于组织代码的文件。

头文件中可以包含变量、函数、结构体、宏等的声明和定义

这样,在其他源文件中,只需要包含头文件就可以使用这些声明和定义,而无需重新编写。

// sample.h// 函数声明
void printMessage();// 宏定义
#define PI 3.14159// 结构体声明
struct Point {int x;int y;
};
3)头文件的保护

为了防止头文件被多次包含,常常在头文件的开头和结尾使用预处理器指令进行保护。

// sample.h
#ifndef SAMPLE_H
#define SAMPLE_H// 头文件内容#endif  // SAMPLE_H

这样,即使同一个头文件被多次包含,也只会在第一次包含时展开。

  • #ifndef#endif 之间的部分是头文件的实际内容。
  • #ifndef 是条件编译指令,用于判断是否定义了宏 SAMPLE_H,如果未定义,则表示这是第一次包含,执行其中的内容。如果已定义该宏,说明头文件已包含过,不再执行后面内容。
  • #define 用于定义宏 SAMPLE_H
  • #endif 表示条件编译结束。
4)示例
// sample.h#ifndef SAMPLE_H
#define SAMPLE_H// 函数声明
void printMessage();// 宏定义
#define PI 3.14159// 结构体声明
struct Point {int x;int y;
};#endif  // SAMPLE_H
// main.c#include <stdio.h>
#include "sample.h"int main() {printMessage();printf("Value of PI: %f\n", PI);struct Point p;p.x = 10;p.y = 20;return 0;
}

上述示例展示了一个简单的头文件,其中包含了函数声明、宏定义和结构体声明。在主程序中使用 #include 引入了这个头文件,使得主程序可以使用头文件中定义的内容。

5)头文件设计原则

包含必要内容: 头文件应该只包含其他源文件需要的声明、定义和结构体等内容,避免将不必要的信息暴露给其他文件

保持简洁: 头文件应该保持简洁,避免包含过多的内容。过大的头文件可能会导致编译时间的增加。

使用预处理器保护: 使用条件编译指令(#ifndef, #define, #endif)来防止头文件被多次包含。

3 #if、#ifdef、ifndef、#elif、#else、#endif

#if#ifdef#ifndef#elif#else#endif 是C语言中的预处理指令,用于条件编译

汇总:

  • #if 用于基于条件,来判断是否编译特定的代码块。
  • #ifdef#ifndef 分别用于检查一个宏是否已经被定义或尚未被定义。
  • #elif 允许在前面的条件不满足时,指定一个新的条件。
  • #else 用于在前面的条件不满足时执行另一段代码。
  • #endif 用于结束条件编译块,必须与之前的 #if#ifdef#ifndef#elif#else 配对使用。
1)#if 指令

#if 指令用于基于条件判断是否编译特定的代码块。条件为一个常量表达式,如果该表达式为真(非零),则执行后面的代码块。

示例:

#define DEBUG 1#if DEBUGprintf("Debug mode is enabled\n");
#endif

在这个例子中,如果 DEBUG 宏被定义为非零值,就会编译 printf 语句。

2)#ifdef#ifndef 指令

#ifdef(if defined)指令用于检查一个宏是否已经被定义。

#ifndef(if not defined)指令用于检查一个宏是否尚未被定义。

#ifdef MACRO// 如果 MACRO 宏已经被定义,执行这部分代码
#endif#ifndef MACRO// 如果 MACRO 宏尚未被定义,执行这部分代码
#endif

示例:

#define DEBUG#ifdef DEBUGprintf("Debug mode is enabled\n");
#endif

在这个例子中,如果 DEBUG 宏被定义,就会编译 printf 语句。

3)#elif 指令

#elif 指令是 #else#if 的组合,用于指定一个新的条件,如果前面的 #if#elif 条件不满足,且当前条件为真,则执行后面的代码块。

示例:

#define DEBUG_LEVEL 2#if DEBUG_LEVEL == 1printf("Debug level is 1\n");
#elif DEBUG_LEVEL == 2printf("Debug level is 2\n");
#elseprintf("Unknown debug level\n");
#endif

在这个例子中,根据 DEBUG_LEVEL 的值不同,选择性地编译不同的 printf 语句。

4)#else 指令

#else 指令用于在前面的条件均不满足时,执行另一段代码。

示例:

#define DEBUG#ifdef DEBUGprintf("Debug mode is enabled\n");
#elseprintf("Debug mode is disabled\n");
#endif

在这个例子中,如果 DEBUG 宏被定义,就会编译第一个 printf 语句,否则编译第二个 printf 语句。

5)#endif 指令

#endif 指令用于结束条件编译块,必须与之前的 #if#ifdef#ifndef#elif#else 配对使用。

示例:

#define DEBUG#ifdef DEBUGprintf("Debug mode is enabled\n");
#elseprintf("Debug mode is disabled\n");
#endif

在这个例子中,#endif 结束了条件编译块。

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

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

相关文章

10 款最适合阅读和注释 PDF 文件的工具

简介 PDF 或便携式文档格式是 Adob​​e 在 20 世纪 90 年代创建的一种文件类型&#xff0c;作为轻松创建和分发文档的解决方案。如今&#xff0c;PDF 在世界各地的教育、企业、政府甚至互联网等行业中得到广泛应用。PDF 具有广泛的功能&#xff0c;包括多页文档、注释、超链接…

环保消毒餐具元宇宙

随着人们生活水平的提高&#xff0c;外卖和快餐已经成为了日常生活中不可或缺的一部分。然而&#xff0c;这些一次性餐具的使用也给环境带来了巨大的压力。为了解决这个问题&#xff0c;环保消毒餐具元宇宙应运而生。 环保消毒餐具元宇宙是一个基于区块链技术的虚拟世界&#…

文件管理小技巧:如何高效整理多种格式的图片,图片分类的方法

随着数字时代的到来&#xff0c;每天都会处理到大量的图片&#xff0c;从个人照片到工作相关的图像资料。如何高效地整理多种格式的图片&#xff0c;常常让人感到困扰。下面看下云炫文件管理器如何对图片分类的方法。 jpg图片、png图片、tiff图片未归类前的缩略图。 jpg图片、…

【已解决】RAR压缩文件可以转换为ZIP格式吗?

想把RAR压缩文件转换成ZIP格式文件&#xff0c;除了可以把RAR压缩包解压后&#xff0c;再重新压缩成ZIP格式&#xff0c;还可以利用WinRAR解压缩软件的“格式转换功能”来实现。不清楚的小伙伴&#xff0c;一起来看看如何操作吧。 首先&#xff0c;通过WinRAR解压缩软件打开RA…

【每日小bug】——mybatis-plus拼接sql空格报错,根据时间聚合查询

mybatis-plus拼接sql报错 复制报错sql语句到navicat,字段之间缺少空格&#xff0c;补上就可以了 聚合sql 根据时间 json接收JsonFormat(timezone "GMT8", pattern "yyyy-MM-dd")DateTimeFormat(pattern "yyyy-MM-dd")private Date startTim…

LeetCode 2085.统计出现过一次的公共字符串:哈希表

【LetMeFly】2085.统计出现过一次的公共字符串&#xff1a;哈希表 力扣题目链接&#xff1a;https://leetcode.cn/problems/count-common-words-with-one-occurrence/ 给你两个字符串数组 words1 和 words2 &#xff0c;请你返回在两个字符串数组中 都恰好出现一次 的字符串的…

DAC模块(MCP44725芯片)

DAC转换模块 MCP4725芯片 I2C.c #include "I2C.h" #include "CS100A.h"/*引脚配置*/ #define MCP4725_SCL_SET HAL_GPIO_WritePin(GPIOF,GPIO_PIN_0,1) #define MCP4725_SCL_RST HAL_GPIO_WritePin(GPIOF,GPIO_PIN_0,0)#define MCP4725_SDA_SET HAL_GPI…

【前后端的那些事】前后端环境搭建+树形结构表格实现

文章目录 1. 前后端项目环境搭建2. table-tree2.1 后端准备2.2 前端准备 前言&#xff1a;最近写项目&#xff0c;发现了一些很有意思的功能&#xff0c;想写文章&#xff0c;录视频把这些内容记录下。但这些功能太零碎&#xff0c;如果为每个功能都单独搭建一个项目&#xff0…

(ros2)gazebo颜色设置

在gazebo当中不用再设置颜色了&#xff0c;因为完全可以使用urdf的设置 <robot name"base" xmlns:xacro"http://wiki.ros.org/wiki/xacro"><xacro:property name"PI" value"3.1415926"/><!--定义一个变量PI&#xff0…

vue前端开发自学,组件的生命周期函数介绍001

vue前端开发自学,组件的生命周期函数介绍001&#xff01;今天介绍一下&#xff0c;组件自身的生命周期函数。又叫做&#xff0c;钩子函数。可以借助于这些钩子函数&#xff0c;实现很多我们预想的效果。比如&#xff0c;在组件渲染 之前&#xff0c;就做一些特殊的操作等等。 …

sectigo通配符dv证书400元买一年送1月实际签发13个月

Sectigo就是众多颁发数字证书的CA认证机构之一&#xff0c;旗下的DV通配符SSL证书作为一种加密通信工具&#xff0c;广泛应用于保护网站数据的安全。其中&#xff0c;SectigoDV通配符SSL证书是一种受欢迎的产品&#xff0c;它不仅能够提供强大的加密功能&#xff0c;还可以提高…

firewalld防火墙命令行工具

firewall-cmd命令 &#xff08;1&#xff09;启动、停止、查看firewalld服务 在安装CentOS 7系统时&#xff0c;会自动安装firewalld 和图形化工具firewall-config.执行以下命令可 以启动 firewalld 并设置为开机自启动状态。 [rootllcgc ~]# systemctl start firewalld.serv…

SpringSecurity入门demo(一)集成与默认认证

一、集成与默认认证&#xff1a; 1、说明&#xff1a;在引入 Spring Security 项目之后&#xff0c;没有进行任何相关的配置或编码的情况下&#xff0c;Spring Security 有一个默认的运行状态&#xff0c;要求在经过 HTTP 基本认证后才能访问对应的 URL 资源&#xff0c;其默认…

1月自考本周末开考!自考考前注意事项及考试技巧

广东省2024年1月高等教育自学考试将于1月13日至14日举行。 注意&#xff1a; 考生应提前至少20分钟进入考场。 开考15分钟后&#xff0c;迟到考生不得进入考场参加当科考试。 2、自考考试必备物品 准考证&#xff1a;进入考场的有效证件&#xff0c;打印后妥善保存 身份证…

C#编程-实现多线程

实现多线程 多线程帮助同时执行各种操作。这为用户节省时间。多线程程序包括一个主线程和其他用户定义的线程以同时执行多个任务。 微处理器为执行的进程分配内存。每个进程占有内存中它们自己的地址空间。但是,所有在进程中的线程占有相同的地址空间。多线程允许在一个程序…

Linux:进程的通信

目录 进程间的通信 管道 1.概念 2.匿名管道 3.命名管道 4.匿名管道与命名管道的区别 5.总结管道的特点 共享内存 1.原理 2.共享内存的建立 3.代码 1.相关函数 2.总结 进程间的通信 1.进程间通信目的 数据传输&#xff1a;一个进程需要将它的数据发送给另一个进程…

软件测试|Beautiful Soup库详细使用指南

简介 Beautiful Soup是一款强大的Python库&#xff0c;广泛用于解析HTML和XML文档&#xff0c;从中提取数据并进行处理。它的灵活性和易用性使得数据抽取变得简单&#xff0c;本文将详细介绍Beautiful Soup库的基本用法和示例。 安装Beautiful Soup 首先&#xff0c;需要确保…

JavaEE学习笔记 2024-1-12 --Tomcat服务器、Servlet

JavaEE JavaEE是企业级开发 是综合性非常强的阶段  包含的知识点:JavaSE,MySQL,JDBC,WEB(HTML,CSS,JS,前端框架),Servlet,JSP,XML,AJAX等技术 1.服务器 JavaEE项目需要运行在服务器之上 WEB服务器就是WEB项目的容器,WEB项目的运行环境,将项目部署到服务器下,可以通过服务器…

Java面试之并发篇(二)

1、前言 本篇主要基于Java面试题之并发篇&#xff08;一&#xff09;继续梳理java中关于并发相关的高频面试题。本篇的面试题基于网络整理&#xff0c;和自己编辑。在不断的完善补充哦。 2、synchronized 的原理是什么? synchronized是 Java 内置的关键字&#xff0c;它提供…

js入口函数和jQuery入口函数的区别

JS入口函数指的是JavaScript中的主入口函数&#xff0c;用来初始化页面加载完成后的操作。通常情况下&#xff0c;JS入口函数是在HTML页面中的<script>标签中定义的&#xff0c;通过onload事件等方式触发调用。 jQuery入口函数则是指使用jQuery库时的主入口函数&#xf…