嵌入式C语言11(宏/程序的编译过程)

⦁ 基本概念

C语言中可以利用宏定义实现文本的快速替换,注意:宏定义是单纯的文本替换,不检查语法是否合法。

C语言标准中提供了很多的预处理指令,比如#include、#pragma…以#开头的都属于预处理指令。
在这里插入图片描述
在这里插入图片描述
预处理指令指的是在gcc编译套件中的cpp预处理器对程序进行编译之前所做的一些动作,比如#include预处理指令就是在程序编译之前由预处理器把包含的头文件中的代码拷贝一份到源文件对应的位置,如果包含的文件中还有其他的预处理指令,会递归执行!
在这里插入图片描述
C语言标准中还提供了#define预处理指令,define是C语言关键字之一,中文具有定义的含义,所以利用#define预处理指令可以对某些表达式、某些常量、某些函数进行定义,其实就是给这些内容起一个可读性较高的名称。

定义格式

在这里插入图片描述
宏替换其实就是简单的文本替换,宏名称就是一个用户命名的特定的标识符,一般实际开发中宏名称都采用大写(潜规则)。 macro 宏

宏名称后面就是用来替换宏名称的替换列表,这个替换列表可以是常量、表达式、if语句以及函数等。

定义格式: #define 宏名称(大写) 替换列表 换行(一般就是用户按下回车)
在这里插入图片描述
用户在源文件中某个位置使用了宏,不管使用了多少次,在程序编译之前,预处理器都会把宏用替换列表进行替换,当然要注意,宏替换就是单纯的文本替换,预处理器并不会做任何检查,比如替换之后是否符合语法,语法的检查是由编译器在编译阶段进行的。
在这里插入图片描述
在这里插入图片描述

使用规则

注意:宏定义的作用域是针对整个文件有效,所以应该定义在源文件的开头部分,这样才可以在其他的函数中使用宏定义,另外,宏不是语句,所以不需要在末尾添加分号,如果添加分号,则分号也会被一起替换。
在这里插入图片描述

具体分类

C语言中宏定义的方案有三种,分别是无参数宏、带参数宏、无替换列表宏,具体如下所示:

(1) 无参数的宏定义
注意:除了用户自定义的宏之外,系统中也存在一些已经定义好的宏,比如常用的NULL就是一个宏,当然,C99标准中还有一些常用的系统预定义的宏:
在这里插入图片描述
(2) 带参数的宏定义
C语言标准中支持定义带参数的宏,带参数的宏的使用在语法上类似于函数调用,宏的参数由括号()进行包含,括号中如果有多个参数则需要通过逗号来分隔,另外,带参数的宏在定义的时候宏名称和参数列表之间不能空格,如下所示:
在这里插入图片描述
可以发现,带参数的宏和函数的形式很像,但是却完全不同,带参数的宏会在程序所有出现的位置进行展开,缺点是浪费了内存空间,但是节约了函数切换的时间。
在这里插入图片描述
(3) 无替换列表的宏

C语言中也允许只定义一个宏,这个宏可以没有替换列表,一般实际开发中都是对程序进行条件编译的情况下来使用。

条件编译指的是可以选择性的编译程序中的某段代码,也就是预处理器可以根据具体的条件来保留或者删除某段源程序。

可以理解为是类似于C语言的判断语句,只不过是使用C语言中的预处理指令来判断宏的有效性,有效性指的是宏是否为真以及宏是否存在,C语言中提供了多种预处理指令来实现条件编译。

在这里插入图片描述
A. #if 用于判断常量表达式是否成立,遵循“非0即真”原则,#if预处理指令作为条件编译
在这里插入图片描述
在这里插入图片描述
一般#if和#endif是结合一起使用的,经常用于程序中的调试,可以选择保留或注释代码块!

B. #ifdef 用于判断宏是否被定义,如果宏是提前定义好的,则该预处理指令是有效的,也需要和#endif一起使用
在这里插入图片描述
C.#if和#elif和#else和#endif 用于条件编译,可以通过常量表达式的多种状态来选择保留或者删除某些代码块
在这里插入图片描述
D. #ifndef和#endif 用于判断宏是否未定义,如果宏定义,则该代码块会被删除,如果宏未被定义,则该代码块可以保留
在这里插入图片描述
在这里插入图片描述

作用范围

思考:宏定义一般定义在源文件的开头,所以作用域是针对整个文件,但是有的时候如果只打算让某个宏只对某个函数有效,请问应该如何实现?

回答:可以实现,可以利用C语言标准中提供的预处理指令#undef,可以提前终止某个宏的作用域。
在这里插入图片描述

程序的编译过程

思考:什么叫做预处理阶段?预处理阶段和编译阶段有什么不同?源文件转换为可执行文件一共需要经历几个阶段?
在这里插入图片描述
预处理:
对源码进行简单的加工,GCC编译器会调用预处理器cpp对程序进行预处理,其实就是解释源程序中所有的预处理指令,如#include(文件包含)、#define(宏定义)、#if(条件编译)等以#号开头的预处理语句。

这些预处理指令将会在预处理阶段被解释掉,如会把被包含的文件拷贝进来,覆盖掉原来的#include语句,把所有的宏定义展开,所有的条件编译语句被执行,GCC还会把所有的注释删掉,添加必要的调试信息。

预处理指令: gcc -E xxx.c -o xxx.i 会生成预处理文件 xxx.i

编译:
就是对经过预处理之后的.i文件进行进一步翻译,也就是对语法、词法的分析,最终生成对应硬件平台的汇编文件,具体生成什么平台的汇编文件取决于编译器,比如X86平台使用gcc编译器,而ARM平台使用交叉编译工具arm-linux-gcc。

编译指令 : gcc -S xxx.i -o xxx.s 会生成汇编文件 xxx.s

汇编:
GCC编译器会调用汇编器as将汇编文件翻译成可重定位文件,其实就是把.s文件的汇编代码翻译为相应的指令。

编译指令 : gcc -c xxx.s -o xxx.o 会生成目标文件 xxx.o

链接:
经过汇编步骤后生成的.o文件其实是ELF格式的可重定位文件,虽然已经生成了指令流,但是需要重定位函数地址等,所以需要链接系统提供的标准C库和其他的gcc基本库文件等,并且还要把其他的.o文件一起进行链接。-lc -lgcc 是默认的,可以省略

编译指令:gcc hello.o -o hello -lc -lgcc 会生成可执行文件 xxx // l是lib的缩写

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

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

相关文章

【湖南大学】2025我们该如何看待DeepSeek

大家好,我是樱木。 DeepSeek 官方网站:https://www.deepseek.com/ 一、DeepSeek 到底是什么? TA 到底厉害在哪里? 故事从 ChatGPT 说起 去年我们看到 Open AI 发布ChatGPT 后,全球的注意力到了 AI 身上。 我们来拆…

【区块链安全 | 第三十三篇】备忘单

文章目录 备忘单操作符优先级备忘单ABI 编码和解码函数bytes 和 string 的成员Address 的成员区块与交易属性校验和断言数学和加密函数合约相关类型信息函数可见性说明符修饰符备忘单 操作符优先级备忘单 以下是操作符的优先级顺序,按评估顺序列出: 优先级描述操作符1后缀递…

Python----计算机视觉处理(Opencv:道路检测之车道线显示)

完整版:Python----计算机视觉处理(Opencv:道路检测完整版:透视变换,提取车道线,车道线拟合,车道线显示) 一、透视变换 将透视变换之后的图像再继续透视变换为原图像 可参考Python----计算机视…

26届Java暑期实习面经,腾讯视频一面

短链接的生成原理 如何解决短链接生成的哈希冲突问题 如何加快从短链接到原链接的重定向过程 TCP 和 UDP 协议 如何理解 TCP 是面向连接的 为什么 TCP 的握手是 3 次 IO 模式 是否有真正写过一个底层的 Socket 通信 MySQL 的事务隔离级别 MVCC 机制 什么叫服务的并行 为什么能基…

Windows注册鼠标钩子,获取用户选中的文本

注册鼠标钩子 // 注册鼠标钩子 HHOOK hMouseHook; hMouseHook SetWindowsHookEx(WH_MOUSE_LL, MouseProc, GetModuleHandle(NULL), 0);// 取消鼠标钩子 UnhookWindowsHookEx(hMouseHook); hMouseHook nullptr; 上述代码中MouseProc方法用于处理系统的鼠标消息 处理鼠标消息…

flink cdc的source数据流如何配置事件时间,如何设置时间语义,分配时间戳并生成水位线

在 Flink CDC 中为 Source 数据流配置事件时间需要结合时间语义设置、时间戳分配和水位线生成三个核心步骤。以下是具体配置方法及注意事项: 1. 设置时间语义 Flink 默认使用处理时间(Processing Time),需显式指定事件时间语义&a…

C++ 指针类型转换全面解析与最佳实践

文章目录 C 指针类型转换全面解析与最佳实践1. 隐式转换基类和派生类指针 2. 显式转换(1) static_cast(2) dynamic_cast(3) reinterpret_cast(4) const_cast 3. C 风格转换4. 常见问题与注意事项5. 总结最佳实践 C 指针类型转换全面解析与最佳实践 在 C 中,指针类型…

批量将 txt/html/json/xml/csv 等文本拆分成多个文件

我们的文本文件太大的时候,我们通常需要对文本文件进行拆分,比如按多少行一个文件将一个大的文本文件拆分成多个小的文本文件。这样我们在打开或者传输的时候都比较方便。今天就给大家介绍一种同时对多个文本文件进行批量拆分的方法,可以快速…

ARM 汇编启动代码详解:从中断向量表到中断处理

ARM 汇编启动代码详解:从中断向量表到中断处理 引言 在嵌入式系统开发中,ARM 处理器(如 Cortex-A 系列)的启动代码是系统初始化和运行的基础。启动代码通常包括中断向量表的创建、初始化硬件状态(如关闭缓存和 MMU&a…

4.7学习总结 可变参数+集合工具类Collections+不可变集合

可变参数: 示例: public class test {public static void main(String[] args) {int sumgetSum(1,2,3,4,5,6,7,8,9,10);System.out.println(sum);}public static int getSum(int...arr){int sum0;for(int i:arr){sumi;}return sum;} } 细节&#xff1a…

2023年蓝桥杯第十四届CC++大学B组真题及代码

目录 1A:日期统计 解析代码_暴力_正解 2B:01串的熵 解析代码_暴力_正解 3C:冶炼金属 解析代码_暴力_正解 4D:飞机降落 解析代码_暴力dfs_正解 5E:接龙数列 解析代码_dp_正解 6F:岛屿个数 解析代…

rom定制系列------小米10pro机型定制解锁固件 原生安卓15批量线刷固件 操作解析与界面预览

注意;固件用于自己机型忘记密码或者手机号注销等出现设备锁 过保修期 售后无视的机型,勿用于非法途径 目前有粉丝联系,自己的机型由于手机号注销导致手机更新系统后出现设备锁界面。另外也没有解锁bl。目前无法使用手机。经过询问是小米10pro机型。根据…

信息学奥赛一本通 1861:【10NOIP提高组】关押罪犯 | 洛谷 P1525 [NOIP 2010 提高组] 关押罪犯

【题目链接】 ybt 1861:【10NOIP提高组】关押罪犯 洛谷 P1525 [NOIP 2010 提高组] 关押罪犯 【题目考点】 1. 图论:二分图 2. 二分答案 3. 种类并查集 【解题思路】 解法1:种类并查集 一个囚犯是一个顶点,一个囚犯对可以看…

我的NISP二级之路-01

目录 一.SSE-CMM系统安全工程-能力成熟度模型(Systems Security Engineering - Capability Maturity Model) 二.ISMS 即信息安全管理体系(Information Security Management System),是一种基于风险管理的、系统化的管理体系 三.Kerberos协议 1. 用户登录与 AS 请求 2…

WEB安全--内网渗透--利用Net-NTLMv2 Hash

一、前言 在前两篇文章中分析了NTLM协议中Net-NTLMv2 Hash的生成、如何捕获Net-NTLMv2 Hash,现在就来探讨一下在内网环境中,如何利用Net-NTLMv2 Hash进行渗透。 二、Net-NTLM Hash的破解 工具:hashcat 原理:利用其内部的字典对…

如何正确使用 `apiStore` 进行 API 管理

在现代前端开发中,API 管理是一个非常重要的环节。apiStore 是一个基于 Pinia 的状态管理工具,它可以帮助我们更高效地管理和调用 API。本文将详细介绍如何正确使用 apiStore,包括如何创建 API 配置文件、在组件中使用 apiStore 以及如何配置…

瓦片数据合并方法

影像数据 假如有两份影像数据 1.全球底层影像0-5级别如下: 2.局部高清影像数据级别9-14如下: 合并方法 将9-14文件夹复制到全球底层0-5的目录下 如下: 然后合并xml文件 使得Tileset设置到最高级(包含所有级别)&…

C++中的类和对象(上)

1 类的定义 1.1 类定义的格式 1 class为定义类的关键字,Stack为类的名字,{}中为类的主体,注意类定义结束时后面分号不能省 略》。类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数…

【Tauri2】013——前端Window Event与创建Window

前言 【Tauri2】012——on_window_event函数-CSDN博客https://blog.csdn.net/qq_63401240/article/details/146909801?spm1001.2014.3001.5501 前面介绍了on_window_event,这个在Builder中的方法,里面有许多事件,比如Moved,Res…

【问题处理】webpack4升webpack5,报错Uncaught ReferrnceError: process is not defined

问题 正在做webpack4升webpack5,项目构建项目成功后在浏览器打开时报错 Uncaught ReferrnceError: process is not defined。 原因 webpack 5 不再自动 polyfill Node.js 的核心模块。 如果你在浏览器运行的代码中使用它,需要从 NPM 中安装兼容模块…