大话C语言:第24篇 预处理

1 C语言编译流程

C语言的编译流程包括:

  • 预编译:将.c 中的头文件展开、宏展开,生成的文件是.i 文件。gcc指令:gcc -E file.c -o file.i

  • 编译:将预处理之后的.i 文件生成 .s 汇编文件。gcc指令:gcc -S file.i –o file.s

  • 汇编:将.s 汇编文件生成.o 目标文件。gcc指令:gcc -c file.s -o file.o

  • 链接:将.o 文件链接成目标文件。gcc -o file file.o

2 #include

  • #include<>//用尖括号包含头文件,在系统指定的路径下找头文件

  • #include "" //用双引号包含头文件,先在当前目录下找头文件,找不到,再到系统指定的路径下找。

注意:预处理只是对 include 等预处理操作进行处理并不会进行语法检查;这个阶段有语法错误也不会报错,编译阶段才进行语法检查。

3 #define

#define是用来定义宏,宏是在预编译的时候进行替换。#define包括:

3.1 不带参宏

语法格式:

#define 宏名 常量

例如,定义圆周率,#define PI 3.14,在预编译的时候如果代码中出现了 PI 就用 3.14 去替换。

#include <stdio.h>

#define PI 3.14

int main()
{
	printf("%lf\n",PI);

    return 0;
}

注意,

  • 只要修改宏定义,其他地方在预编译的时候就会重新替换。

  • 宏定义后边不要加分号。

  • 宏定义的作用范围,从定义的地方到本文件末尾。

如果想在中间终止宏的定义范围,可以使用#undef。例如,终止刚定义的PI,#undef PI

#include <stdio.h>

#define PI 3.14

int main()
{
		printf("%lf\n",PI);

#undef PI

#define PI 3.1415

		printf("%lf\n",PI);
	
    return 0;
}

3.2 带参宏

语法格式:

// 表达式是由参数1至参数n构成
#define 宏名(参数1,参数2,...,参数n) 表达式

例如,两数相乘,#define Sum(num1, num2) num1*num2

#include <stdio.h>

#define Sum(num1, num2)  num1*num2

int main(int argc, char *argv[])
{
    int result = Sum(10,20);
    printf("result=%d\n", result);
    
    return 0;
}

实际上,带参数的宏只做简单的参数替换,上述案例中,Sum(10,20),本质上,10*20;如果我们传入的Sum(10+6, 20)的话,宏展开后,10+6 * 20。

#include <stdio.h>

#define Sum(num1, num2)  num1*num2

int main(int argc, char *argv[])
{
    int result = Sum(10+6, 20);
    printf("result=%d\n", result);
    
    return 0;
}

要解决上述问题,最好的办法就是对每个参数单独使用(),改进一下上述代码

#include <stdio.h>

#define Sum(num1, num2)  (num1) * (num2)

int main(int argc, char *argv[])
{
    int result = Sum(10+6, 20);
    printf("result=%d\n", result);
    
    return 0;
}

注意,带参宏被调用多少次就会展开多少次,执行代码的时候没有函数调用的过程,不需要压栈弹栈。所以带参宏,是浪费了空间,因为被展开多次,节省时间。

4 选择性编译

        选择性编译是指在编译过程中,根据特定的条件或环境的不同,选择性地让特定的代码语句有效或无效。这种编译方式允许开发者在不同的环境或配置下编译不同的代码,以实现灵活的程序控制和功能切换。

        在C语言中,选择性编译通常通过预处理器指令来实现,如#ifdef、#ifndef、#else和#endif等。这些指令可以在预处理阶段根据是否定义了某个宏,来决定是否编译特定的代码段。例如,在开发环境中可能需要打印调试信息,而在生产环境中则不需要,通过选择性编译可以在生产环境中排除这些打印语句,以提高程序的运行效率。

        选择性编译的主要作用是防止头文件重复定义和代码编译冗余,从而确保程序的正确性和效率。同时,它也使程序更加灵活和可配置,可以根据不同的需求和环境进行定制。

4.1 #ifdef

语法格式:

#ifdef XXX
	// 功能代码1
#else
	// 功能代码2
#endif

如果已经定义过 XXX(建议取有意义名字) ,就编译功能代码1,否则编译功能代码1。

#include <stdio.h>

#define LANG

int main(int argc, char *argv[])
{
    #ifdef LANG
    	printf("hello world!!\n");
    #else
    	printf("世界,你好!\n");
    #endif
    
    return 0;
}

4.2 #ifndef

语法格式:

#ifndef XXX
	// 功能代码1
#else
	// 功能代码2
#endif

这种方式是和第一种互补,例如

#include <stdio.h>

// #define LANG

int main(int argc, char *argv[])
{
    #ifdef LANG
    	printf("hello world!!\n");
    #else
    	printf("世界,你好!\n");
    #endif
    
    return 0;
}

4.3 #if

语法格式:

#if 表达式
	// 功能代码1
#else
	// 功能代码2
#endif

如果表达式为真,编译功能代码1,否则编译功能代码2。例如

#define DEBUG 1  
  
int main() 
{  
#if DEBUG  
    // 功能代码1: 调试用的代码  
    printf("调试代码.\n");  
#else  
    // 功能代码2: 不包含调试的代码  
    printf("关闭调试代码.\n");  
#endif  
    
    return 0;  
}

注意,如果DEBUG定义为0,表达式为假(false),执行#else。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

逢3必过报数游戏-第13届蓝桥杯省赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第84讲。 逢3必过报数游戏&…

直流放大器

一&#xff0c;概念及存在问题 集成电路主要由半导体材料构成&#xff0c;其内部适合用二极管&#xff0c;三极管等类型的元器件制作&#xff0c;而不适用电容&#xff0c;电感和变压器&#xff0c;因此集成放大电路内部多个放大电路之间通常采用直接耦合。直接耦合电路除了可…

文生视频新王登场:Luma官宣免费、电影级大片生成,Sora?可灵?SD3.0?(内附网址)

✨点击这里✨&#xff1a;&#x1f680;原文链接&#xff1a;&#xff08;更好排版、视频播放、社群交流、最新AI开源项目、AI工具分享都在这个公众号&#xff01;&#xff09; 文生视频新王登场&#xff1a;Luma官宣免费、电影级大片生成&#xff0c;Sora&#xff1f;可灵&am…

TJA1145休眠唤醒调试

目录 项目场景:TJA1145引脚图问题描述SPI链路验证休眠唤醒休眠唤醒配置唤醒报文配置代码相关寄存器:模式寄存器使能CAN唤醒设置唤醒边沿检测事件状态及捕获寄存器CANFD报文不会被识别为有效的唤醒帧项目场景: 最近开发过程中,选择了这颗芯片,踩了很多坑,总算是把这个芯片…

基于RandLA-Net深度学习模型的激光点云语义分割

一、场景要素语义分割部分的文献阅读笔记 RandLA-Net是一种高效、轻量级的神经网络&#xff0c;其可直接逐点推理大规模点云的语义标签。RandLA-Net基于随机点采样获得了显著的计算和内存效率&#xff0c;并采用新的局部特征聚合模块有效地保留了几何细节&#xff0c;弥补了随机…

【报错】无法找到模块“element-plus/es/locale/index.mjs”的声明文件。

报错&#xff1a; 无法找到模块“element-plus/es/locale/index.mjs”的声明文件。“E:/codeAll/work/test1/test2/HealinLikeMe-ui/node_modules/.pnpm/element-plus2.7.3_vue3.4.27_typescript5.4.5_/node_modules/element-plus/es/locale/index.mjs”隐式拥有 "any&quo…

51 USART数据收发

1.0 USART实现单个数据收发 串口启动之前需要对串口进行初始化&#xff0c;主要是设置产生波特率的定时器1&#xff0c;使用串口的工作方式还是中断的工作方式具体的配置步骤如下所示。 注&#xff1a; 1&#xff1a; 确定TMOD &#xff08;定时器模式寄存器&#xff09; 确…

vue3医疗项目

配置src别名 打开viteconfig.js文件进行配置 import { defineConfig } from "vite"; import vue from "vitejs/plugin-vue"; // 引入node提供内置模块path&#xff1a;可以获取绝对路径 import path from "path";// https://vitejs.dev/config…

Lexar NM620 512GB SSD PCIE3.0 X4测评

Lexar NM620 512GB SSD PCIE3.0 X4测评 官方可选容量256GB~2TB PCIE 3.0X4 支持NVME 1.4协议 CDM顺序Read速度3448MB\s CDM顺序Write速度2626MB\s CDM 4K随机Read速度465MB\s CDM 4K随机Write速度602MB\s AS SSD顺序Read速度为2855MB\s AS SSD顺序Write速度为2331MB\s AS SSD…

增值税发票OCR识别API在Java、Python、PHP中的使用教程

​增值税发票OCR识别是一种利用光学字符识别&#xff08;OCR&#xff09;技术&#xff0c;自动提取和识别增值税发票上的文字信息的过程。增值税发票是企业在销售商品或提供服务过程中产生的一种税务凭证&#xff0c;包含了关键的财务信息&#xff0c;如商品明细、金额、税率等…

紫光展锐5G处理器T750__国产手机芯片5G方案

展锐T750核心板采用6nm EUV制程工艺&#xff0c;CPU架构采用了八核设计&#xff0c;其中包括两个主频为2.0GHz的Arm Cortex-A76性能核心和六个主频为1.8GHz的A55小核。这种组合使得T750具备卓越的处理能力&#xff0c;并能在节能的同时提供出色的性能表现。该核心模块还搭载了M…

推荐一款可以下载B站视频和音频的工具

cobalt是一个免费的下载网站&#xff0c;主要是用于载视频和音频。只要你把相应的网址复制下来&#xff0c;然后打开cobalt网站&#xff0c;黏贴网址&#xff0c;选择要下载的格式&#xff0c;就可以下载相应的音频或者视频了。 该网站非常简洁&#xff0c;使用也很简单。目前只…

Android入门第69天-AndroidStudio中的Gradle使用国内镜像最强教程

背景 AndroidStudio默认连接的是dl.google的gadle仓库。 每次重新build时: 下载速度慢;等待了半天总时build faild;build到一半connection timeout;即使使用了魔法也难以一次build好;这严重影响了我们的学习、开发效率。 当前网络上的使用国内镜像的教程不全 网上的教程…

MATLAB画图时添加标注显示有效数字的位数,可以编辑此函数

本来系统有个函数&#xff0c;在图像窗口选择标注工具&#xff0c;再在图像窗口右击鼠标&#xff0c;选择"编辑文本更新函数..."&#xff0c;即打开系统的设置函数&#xff0c;可以修改最后一行&#xff1a; formattedValue [valueFormat num2str(value,4) removeV…

【网络编程】进程间的通信

进程间通信意味着两个不同进程间交换数据&#xff0c;操作系统中应提供两个进程可以同时访问内存空间。 管道实现进程间通信 管道不属于进程资源&#xff0c;与套接字一样属于操作系统。两个进程通过操作系统提供内存空间进行通信 #include<unistd.h> int pipe(int fil…

如何下载Tuxera NTFS for Mac 2023软件及详细安装步骤

软件简介&#xff1a; 在 Mac 上打开、编辑、复制、移动或删除存储在 Windows NTFS 格式 USB 驱动器上的文件。当您获得一台新 Mac 时&#xff0c;它只能读取 Windows NTFS 格式的 USB 驱动器。要将文件添加、保存或写入您的 Mac&#xff0c;您需要一个附加的 NTFS 驱动程序。…

Qt C++ TCP服务端响应多客户端通讯

本示例使用的设备&#xff1a;WIFI无线4G网络RFID云读卡器远程网络开关物流网阅读器TTS语音-淘宝网 (taobao.com) #include "mainwindow.h" #include "ui_mainwindow.h" #include "QMessageBox" #include <QDebug> #include <exceptio…

Guitar Pro8 最新详细安装步骤 及解析

随着音乐文化的普及和发展&#xff0c;越来越多的人开始关注和学习吉他。而在吉他学习的道路上&#xff0c;一款优质的吉他软件无疑会给我们带来极大的便利和帮助。今天&#xff0c;我们就来探讨一款备受好评的吉他软件——Guita Pro8&#xff0c;看看它究竟有何魅力之处。 Gu…

NettyのNIOBIO原理解析

1、IO模型 在IO模型中&#xff0c;主要可分为同步与异步操作&#xff1a; 在同步 I/O 模型中&#xff0c;I/O 操作是阻塞的&#xff0c;当一个进程或线程执行 I/O 操作时&#xff0c;它会一直等待这个操作完成才继续执行后续的代码。 在异步 I/O 模型中&#xff0c;I/O 操作是非…

Google Earth Engine(GEE)——在控制台上答应出一个button按钮

函数: ui.Button(label, onClick, disabled, style) A clickable button with a text label. Arguments: label (String, optional): The buttons label. Defaults to an empty string. onClick (Function, optional): A callback fired when the button is clicked. T…