C 语言预处理器

C 语言预处理器

在本教程中,将向您介绍c预处理器,并在示例的帮助下学习使用#include,#define和条件编译。C预处理程序是一个宏预处理程序(允许您定义宏),可以在编译程序之前对其进行转换。这些转换可以包括头文件,宏扩展等。所有预处理指令均以#符号开头。

C 预处理器不是编译器的组成部分,但是它是编译过程中一个单独的步骤。简言之,C 预处理器只不过是一个文本替换工具而已,它们会指示编译器在实际编译之前完成所需的预处理。我们将把 C 预处理器(C Preprocessor)简写为 CPP。

所有的预处理器命令都是以井号(#)开头。它必须是第一个非空字符,为了增强可读性,预处理器指令应从第一列开始。下面列出了所有重要的预处理器指令:

指令描述
#define定义宏
#include包含一个源代码文件
#undef取消已定义的宏
#ifdef如果宏已经定义,则返回真
#ifndef如果宏没有定义,则返回真
#if如果给定条件为真,则编译下面代码
#else#if 的代替方案
#elif如果前面的 #if 给定条件不为真,当前条件为真,则编译下面代码
#endif结束一个 #if……#else 条件编译块
#error当遇到标准错误时,输出错误消息
#pragma使用标准化方法,向编译器发布特殊的命令到编译器中

预处理器示例

分析下面的示例来理解不同的指令。

#define MAX_ARRAY_LENGTH 20

这个指令告诉 CPP 把所有的 MAX_ARRAY_LENGTH 替换为 20。使用 #define 定义常量来增强可读性。

#include <stdio.h>
#include "myheader.h"

这些指令告诉 CPP 从系统库中获取 stdio.h,并添加文本到当前的源文件中。下一行告诉 CPP 从本地目录中获取 myheader.h,并添加内容到当前的源文件中。

#undef  FILE_SIZE
#define FILE_SIZE 42

这个指令告诉 CPP 取消已定义的 FILE_SIZE,并定义它为 42。

#ifndef MESSAGE#define MESSAGE "You wish!"
#endif

这个指令告诉 CPP 只有当 MESSAGE 未定义时,才定义 MESSAGE。

#ifdef DEBUG/* Your debugging statements here */
#endif

这个指令告诉 CPP 如果定义了 DEBUG,则执行处理语句。在编译时,如果您向 gcc 编译器传递了 -DDEBUG 开关量,这个指令就非常有用。它定义了 DEBUG,您可以在编译期间随时开启或关闭调试。

预定义宏

ANSI C 定义了许多宏。在编程中您可以使用这些宏,但是不能直接修改这些预定义的宏。

描述
DATE当前日期,一个以 “MMM DD YYYY” 格式表示的字符常量。
TIME当前时间,一个以 “HH:MM:SS” 格式表示的字符常量。
FILE这会包含当前文件名,一个字符串常量。
LINE这会包含当前行号,一个十进制常量。
STDC当编译器以 ANSI 标准编译时,则定义为 1。

让我们来尝试下面的示例:

#include <stdio.h>
main()
{printf("File :%s\n", __FILE__ );printf("Date :%s\n", __DATE__ );printf("Time :%s\n", __TIME__ );printf("Line :%d\n", __LINE__ );printf("ANSI :%d\n", __STDC__ );
}

当上面的代码(在文件 test.c 中)被编译和执行时,它会产生下列结果:

File :test.c
Date :Jun 2 2012
Time :03:36:24
Line :8
ANSI :1

预处理器运算符

C 预处理器提供了下列的运算符来帮助您创建宏:

宏延续运算符(\)

一个宏通常写在一个单行上。但是如果宏太长,一个单行容纳不下,则使用宏延续运算符(\)。例如:

#define  message_for(a, b)  \printf(#a " and " #b ": We love you!\n")

字符串常量化运算符(#)

在宏定义中,当需要把一个宏的参数转换为字符串常量时,则使用字符串常量化运算符(#)。在宏中使用的该运算符有一个特定的参数或参数列表。例如:

#include <stdio.h>
#define  message_for(a, b)  \printf(#a " and " #b ": We love you!\n")
int main(void)
{message_for(Carole, Debra);return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

Carole and Debra: We love you!

标记粘贴运算符(##)

宏定义内的标记粘贴运算符(##)会合并两个参数。它允许在宏定义中两个独立的标记被合并为一个标记。例如:

#include <stdio.h>
#define tokenpaster(n) printf ("token" #n " = %d", token##n)
int main(void)
{int token34 = 40;tokenpaster(34);return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

token34 = 40

这是怎么发生的,因为这个示例会从编译器产生下列的实际输出:

printf ("token34 = %d", token34);

这个示例演示了 token##n 会连接到 token34 中,在这里,我们使用了字符串常量化运算符(#)标记粘贴运算符(##)

defined() 运算符

预处理器 defined 运算符是用在常量表达式中的,用来确定一个标识符是否已经使用 #define 定义过。如果指定的标识符已定义,则值为真(非零)。如果指定的标识符未定义,则值为假(零)。下面的示例演示了 defined() 运算符的用法:

#include <stdio.h>
#if !defined (MESSAGE)#define MESSAGE "You wish!"
#endif
int main(void)
{printf("这是消息: %s\n", MESSAGE);  return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

这是消息: You wish!

参数化的宏

CPP 一个强大的功能是可以使用参数化的宏来模拟函数。例如,下面的代码是计算一个数的平方:

int square(int x) {return x * x;
}

我们可以使用宏重写上面的代码,如下:

#define square(x) ((x) * (x))

在使用带有参数的宏之前,必须使用 #define 指令定义。参数列表是括在圆括号内,且必须紧跟在宏名称的后边。宏名称和左圆括号之间不允许有空格。例如:

#include <stdio.h>
#define MAX(x,y) ((x) > (y) ? (x) : (y))
int main(void)
{printf("10到20之间的最大值是 %d\n", MAX(10, 20));  return 0;c
}

当上面的代码被编译和执行时,它会产生下列结果:

1020之间的最大值是 20

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

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

相关文章

vue3如何判断是不是响应式数据

isRef: 检查一个值是否为一个 ref 对象 isReactive: 检查一个对象是否是由 reactive 创建的响应式代理 isReadonly: 检查一个对象是否是由 readonly 创建的只读代理 isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理 <template><div>&l…

allure修改logo 自定义

无论pytest还是httprunner都适用allure生成报告。那我们就有必要对allure报告进行一些定制。我们先修改logo&#xff1a; 1、给allure.yml插件custom-logo-plugin 找到allure安装的位置&#xff0c;在config文件夹下有一个allure.yml的配置文件。打开它&#xff0c;在最后添加…

Python接口自动化测试 ---Allure报告使用详解

这一节主要是记录allure的内容以及用法&#xff0c;怎么让他生成一个完整的想要的报告。 allure生成的报告和其他五花八门的报告对比了一下&#xff0c;它的可读性是最好、最直观的。这不仅仅是我想要的效果&#xff0c;也是很多小伙伴想要的结果&#xff0c;毕竟这是给领导看…

扩散模型DDPM学习笔记

扩散模型DDPM 文章目录 扩散模型DDPM如何运作基本概念训练过程推理过程&#xff1a; 目标损失函数推导评估标准 论文地址&#xff1a; Denoising Diffusion Probabilistic Models (DDPM) 如何运作 ​ 从guassian distribution进行采样得到一个噪声的图片&#xff0c;图片大小…

【复杂网络建模】——ER网络度分布、无标度网络度分布

目录 一、复杂网络介绍 二、ER网络、SF网络介绍 1、ER网络(Erdős-Rnyi网络)

测开笔记--Typescript: 文件复制到指定目录

开发背景&#xff1a; 自动化开发语言使用的是TypeScript&#xff1b;框架用的是playwright。有个测试脚本需要先将几个文件复制粘贴到新建的项目文件夹下&#xff0c;系统会读取该文件&#xff0c;然后生成页面信息。 关键字&#xff1a;文件复制粘贴&#xff1b; 新建的项目…

为什么我不能给shopify的图片添加alt

首先我们要明白是什么ALT标签&#xff0c;为什么要添加这个标签&#xff0c;这个标签有什么用 ALT标签是什么 ALT属性是HTML的一部分&#xff0c;它为那些无法查看图像的用户提供替代的文本描述。 ALT标签有什么用 使用ALT属性还可以帮助搜索引擎爬虫更好地理解您的网站内容。有…

SpringBoot配置多个不同Thymeleaf模板位置

最近开发当中需要在SpringBoot配置多个不同Thymeleaf位置&#xff0c;特此记录下相关过程 默认Thymeleaf配置 当我们集成thymeleaf后&#xff0c;会有一个默认的配置信息,可以在配置文件当中配置默认的信息&#xff0c;修改路径&#xff0c;前后缀等等参数 spring:thymeleaf…

华为OD机试 - 小华地图寻宝(Java JS Python C)

题目描述 小华按照地图去寻宝,地图上被划分成 m 行和 n 列的方格,横纵坐标范围分别是 [0, n-1] 和 [0, m-1]。 在横坐标和纵坐标的数位之和不大于 k 的方格中存在黄金(每个方格中仅存在一克黄金),但横坐标和纵坐标之和大于 k 的方格存在危险不可进入。小华从入口 (0,0) …

学习知识回顾随笔(远程连接MySQL|远程访问Django|HTTP协议|Web框架)

文章目录 如何远程连接MySQL数据库1.创建用户来运行&#xff0c;此用户从任何主机连接到mysql数据库2.使用IP地址来访问MySQL数据库 如何远程访问Django项目Web应用什么是Web应用应用程序的两种模式Web应用程序的优缺点 HTTP协议&#xff08;超文本传输协议&#xff09;简介HTT…

Airtest自动化测试工具实战演练

一开始知道Airtest大概是在年初的时候&#xff0c;当时&#xff0c;看了一下官方的文档&#xff0c;大概是类似Sikuli的一个工具&#xff0c;主要用来做游戏自动化的&#xff0c;通过截图的方式用来解决游戏自动化测试的难题。最近&#xff0c;移动端测试的同事尝试用它的poco库…

LCM-LoRA模型推理简明教程

潜在一致性模型 (LCM) 通常可以通过 2-4 个步骤生成高质量图像&#xff0c;从而可以在几乎实时的设置中使用扩散模型。 来自官方网站&#xff1a; LCM 只需 4,000 个训练步骤&#xff08;约 32 个 A100 GPU 小时&#xff09;即可从任何预训练的稳定扩散 (SD) 中提取出来&#…

sed文本 免交互

目录 什么是sed 概念 格式 基本用法 命令的选项 打印第三行 打印日志文件 打印奇数行 打印偶数行 第三行退出 删除第三行 sed在不打开文件的情况下修改文件内容 在后面添加 选项a 在字符中间添加 \n 实现追加换行 全部追加 在前面插入 选项i 替换 选项c …

HIVE SQL建表常用数据类型一览

类型描述BOOLEANtrue/falseTINYINTtrue/1字节的有符号整数 -128~127SMALLINT2个字节的有符号整数&#xff0c;-32768~32767INT4个字节的带符号整数BIGINT8字节带符号整数FLOAT4字节单精度浮点数DOUBLE8字节双精度浮点数DEICIMAL任意精度的带符号小数STRING字符串&#xff0c;变…

第二题-差值-【第六届传智杯程序设计挑战赛解题分析详解复盘】(JavaPythonC++实现)

🚀 欢迎来到 ACM 算法题库专栏 🚀 在ACM算法题库专栏,热情推崇算法之美,精心整理了各类比赛题目的详细解法,包括但不限于ICPC、CCPC、蓝桥杯、LeetCode周赛、传智杯等等。无论您是刚刚踏入算法领域,还是经验丰富的竞赛选手,这里都是提升技能和知识的理想之地。 ✨ 经典…

Java精品项目源码基于SpringBoot的智慧园区管理系统(v67)

Java精品项目源码基于SpringBoot的智慧园区管理系统(v67) 大家好&#xff0c;小辰今天给大家介绍一个智慧园区管理系统&#xff0c;演示视频公众号&#xff08;小辰哥的Java&#xff09;对号查询观看即可 文章目录 Java精品项目源码基于SpringBoot的智慧园区管理系统(v67)难度…

vmware系列:【VMware篇】8-vCenter的安装与配置(一)以IP地址安装

【VMware篇】8-vCenter的安装与配置(一)以IP地址安装 vmware系列文章链接第1章前言第2章安装前准备第3章安装步骤一、第一阶段二、打开主机shell、SSH三、添加域名解析四、第二阶段五、设置密码过期时间六、新建集群添加主机vmware系列文章链接 VMware官网下载注册: VMware…

【图像分割】【深度学习】PFNet官方Pytorch代码-PFNet网络损失函数模块解析

【图像分割】【深度学习】PFNet官方Pytorch代码-PFNet网络损失函数模块解析 文章目录 【图像分割】【深度学习】PFNet官方Pytorch代码-PFNet网络损失函数模块解析前言PM定位模块损失函数FM聚焦模块损失函数总结 前言 在详细解析PFNet代码之前&#xff0c;首要任务是成功运行PF…

压缩包文件丢失?4个正确找回方法分享!

“我有一个很重要的压缩包保存在电脑上&#xff0c;但是不知道为什么里面有些文件丢失了。有什么方法可以快速找回压缩文件&#xff1f;请大家给我支支招吧&#xff01;” 如果我们的文件太多&#xff0c;将它们放在压缩包中不仅能让文件更有序&#xff0c;还能更合理的节省电脑…

LD_PRELOAD劫持

LD_PRELOAD劫持 <1> LD_PRELOAD简介 LD_PRELOAD 是linux下的一个环境变量。用于动态链接库的加载&#xff0c;在动态链接库的过程中他的优先级是最高的。类似于 .user.ini 中的 auto_prepend_file&#xff0c;那么我们就可以在自己定义的动态链接库中装入恶意函数。 也…