【机器学习智能硬件开发全解】(九)—— 政安晨:通过ARM-Linux掌握基本技能【C语言程序的预处理过程】

news2024/11/28 6:28:37

政安晨的个人主页政安晨

欢迎 👍点赞✍评论⭐收藏

收录专栏机器学习智能硬件开发全解

希望政安晨的博客能够对您有所裨益,如有不足之处,欢迎在评论区提出指正!

C语言程序的预处理过程是在编译阶段之前进行的,主要包括以下几个步骤

  1. 去除注释预处理器会将程序中的注释去除,不会传递给编译器。

  2. 头文件包含预处理器会根据程序中的#include指令,将对应的头文件内容插入到程序中。这样可以方便地使用已经定义好的变量、函数等。

  3. 宏替换预处理器会根据程序中定义的宏,将宏的引用替换为相应的内容。例如,将宏定义的常数替换为实际的数值,将宏定义的函数调用替换为函数体。

  4. 条件编译预处理器会根据程序中的条件编译指令,决定是否编译相应的代码段例如,根据条件判断是否编译某个平台的特定代码。

  5. 处理特殊指令预处理器还可以处理特殊的预处理指令,例如#define#ifdef等,对程序代码进行进一步的处理。

预处理器处理完程序后,生成的预处理文件会被传递给编译器进行编译。


预处理过程

为了方便编程,编译器一般为开发人员提供一些预处理命令,使用#标识。

我们常见的预处理命令如下:

● 头文件包含:#include。

● 定义一个宏:#define。

● 条件编译:#if、#else、#endif。

● 编译控制:#pragma。

编译器提供的这些预处理命令,大大方便了程序的编写:

通过头文件包含可以实现模块化编程;

使用宏可以定义一个常量,提高程序的可读性;

通过条件编译可以让代码兼容不同的处理器架构和平台,以最大限度地复用公用代码。

通过#pragma预处理命令可以设定编译器的状态,指示编译器完成一些特定的动作

#pragma pack([n]):指示结构体和联合成员的对齐方式。

#pragma message("string"):在编译信息输出窗口打印自己的文本信息。

#pragma warning:有选择地改变编译器的警告信息行为。

#pragma once:在头文件中添加这条指令,可以防止头文件多次编译。

预处理过程,其实就是在编译源程序之前,先处理源文件中的各种预处理命令

编译器是不认识预处理指令的,在编译之前不先把这些预处理命令处理掉,编译器就会报错。

预处理主要包括以下操作

头文件展开:将#include包含的头文件内容展开到当前位置。

宏展开:展开所有的宏定义,并删除#define。

条件编译:根据宏定义条件,选择要参与编译的分支代码,其余的分支丢弃。

● 删除注释。

添加行号和文件名标识:编译过程中根据需要可以显示这些信息。

保留#pragma命令:该命令会在程序编译时指示编译器执行一些特定行为。

一个源程序在预处理前后有什么变化呢?

重写前面的C程序

我们写了一个测试程序,分别使用预处理命令去定义一些宏和条件编译。

咱们在上一篇文章中代码的基础上修改一下)上一篇文章:

【机器学习智能硬件开发全解】(八)—— 政安晨:通过ARM-Linux掌握基本技能【C语言程序的编译/链接/安装运行】icon-default.png?t=N7T8https://blog.csdn.net/snowdenkeke/article/details/136805174对上一章中的main.c文件重写如下:

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

#define PI 3.14

int global_val = 1;
int uninit_val;

void platform_init()
{
#ifdef ARM
        printf("ARM platform init ... \n");
#else
        printf("X86 platform init ... \n");
#endif

        return;
}

#pragma pack(2)
#pragma message("build main.c ...\n")

float f = PI;

int main(void)
{
        platform_init();

        int a, b;
        static int local_val = 2;
        static int uninit_local_val;

        a = add(2, 3);
        b = sub(5, 4);

        printf("a = %d\n", a);
        printf("b = %d\n", b);

        return 0;
}

对上面的C程序只作预处理操作,不编译,将输出的信息重定向到main.i文件。

## 在命令行控制台执行下面命令,并将预编译的信息写入main.i文件中
arm-linux-gnueabihf-gcc -E main.c > main.i

## 查看预编译文件
cat main.i

main.i中的部分信息如下:

# 0 "main.c"
# 0 "<built-in>"
# 0 "<command-line>"
# 1 "/usr/arm-linux-gnueabihf/include/stdc-predef.h" 1 3
# 0 "<command-line>" 2
# 1 "main.c"
# 1 "/usr/arm-linux-gnueabihf/include/stdio.h" 1 3
# 27 "/usr/arm-linux-gnueabihf/include/stdio.h" 3
# 1 "/usr/arm-linux-gnueabihf/include/bits/libc-header-start.h" 1 3
# 33 "/usr/arm-linux-gnueabihf/include/bits/libc-header-start.h" 3
# 1 "/usr/arm-linux-gnueabihf/include/features.h" 1 3
# 392 "/usr/arm-linux-gnueabihf/include/features.h" 3
# 1 "/usr/arm-linux-gnueabihf/include/features-time64.h" 1 3
# 20 "/usr/arm-linux-gnueabihf/include/features-time64.h" 3
# 1 "/usr/arm-linux-gnueabihf/include/bits/wordsize.h" 1 3
# 21 "/usr/arm-linux-gnueabihf/include/features-time64.h" 2 3
# 1 "/usr/arm-linux-gnueabihf/include/bits/timesize.h" 1 3
# 22 "/usr/arm-linux-gnueabihf/include/features-time64.h" 2 3
# 393 "/usr/arm-linux-gnueabihf/include/features.h" 2 3
# 489 "/usr/arm-linux-gnueabihf/include/features.h" 3
# 1 "/usr/arm-linux-gnueabihf/include/sys/cdefs.h" 1 3
# 559 "/usr/arm-linux-gnueabihf/include/sys/cdefs.h" 3
# 1 "/usr/arm-linux-gnueabihf/include/bits/wordsize.h" 1 3
# 560 "/usr/arm-linux-gnueabihf/include/sys/cdefs.h" 2 3
# 1 "/usr/arm-linux-gnueabihf/include/bits/long-double.h" 1 3
# 561 "/usr/arm-linux-gnueabihf/include/sys/cdefs.h" 2 3
# 490 "/usr/arm-linux-gnueabihf/include/features.h" 2 3
# 513 "/usr/arm-linux-gnueabihf/include/features.h" 3
# 1 "/usr/arm-linux-gnueabihf/include/gnu/stubs.h" 1 3
# 10 "/usr/arm-linux-gnueabihf/include/gnu/stubs.h" 3
# 1 "/usr/arm-linux-gnueabihf/include/gnu/stubs-hard.h" 1 3
# 11 "/usr/arm-linux-gnueabihf/include/gnu/stubs.h" 2 3
# 514 "/usr/arm-linux-gnueabihf/include/features.h" 2 3
# 34 "/usr/arm-linux-gnueabihf/include/bits/libc-header-start.h" 2 3
# 28 "/usr/arm-linux-gnueabihf/include/stdio.h" 2 3

......
......
......

# 2 "main.c" 2
# 1 "sub.h" 1

# 1 "sub.h"
int add(int nCountA, int nCountB);
int sub(int nCountA, int nCountB);
# 3 "main.c" 2



int global_val = 1;
int uninit_val;

void platform_init()
{



 printf("X86 platform init ... \n");


 return;
}

#pragma pack(2)

# 21 "main.c"
#pragma message("build main.c ...\n");
float f = 3.14;

int main(void)
{
 int a, b;
 static int local_val = 2;
 static int uninit_local_val;

 a = add(2, 3);
 b = sub(5, 4);

 printf("a = %d\n", a);
 printf("b = %d\n", b);

 return 0;
}

通过预处理前后源文件的变化对比,我们可以看到

当预处理器遇到#include命令时,会直接将包含的头文件内容展开,并删除#include;

当遇到#define宏时,执行同样的操作。

当遇到条件编译指令时,会根据开发者定义的宏标记,选择要参与编译的代码部分,其余部分删除,经过预处理后,#pragma保留,指示编译器在后续的编译阶段执行一些特定的操作。

继续编译预处理后的C程序,在编译信息提示窗口里,我们会看到自己添加的编译提示信息。


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

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

相关文章

基础-笔试题6

1、tcp/udp是属于哪一层&#xff1f;tcp/udp有何优缺点&#xff1f; tcp /udp属于运输层 TCP 服务提供了数据流传输、可靠性、有效流控制、全双工操作和多路复用技术等。 与 TCP 不同&#xff0c; UDP 并不提供对 IP 协议的可靠机制、流控制以及错误恢复功能等。由于 UDP 比较…

[Qt学习笔记]Qt鼠标事件mouseMoveEvent实时获取图像的坐标和像素值

目录 1、介绍2、效果展示3、实现过程3.1 图像的加载和显示3.2 设置鼠标跟踪事件激活3.3 实现代码 4、源码展示 1、介绍 上一篇介绍了使用OpenCV的setMouseCallback回调函数实现获取鼠标点击点的图像坐标和像素值&#xff0c;本篇使用鼠标事件mouseMoveEvent函数来实现实时获取…

vue3+element Plus form 作为子组件,从父组件如何赋值?

刚开始接触vue3时&#xff0c;碰到一个很low的问题&#xff0c;将form作为子组件&#xff0c;在页面中给form表单项输入内容&#xff0c;输入框不显示值&#xff0c;知道问题出在哪&#xff0c;但因为vue3组合式api不熟悉&#xff0c;不知从哪下手... 效果图&#xff1a; 父组…

如何在iOS系统抓取log

前言&#xff1a;因为作者目前工作领域和苹果智能家居有关&#xff0c;然后发现一些bug其实是apple sdk原生code的问题&#xff0c;所以需要给apple提radar单&#xff0c;就需要抓ios端Log充当证据给apple看&#xff0c;其实ios抓log非常简单&#xff0c;大家感兴趣可以学习下哦…

Python条件语句深度解析:从基础到应用的全面指南

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! ​ 目录 &#x1f4d8; 一、引言 &#x1f4dd; 二、…

【Flutter】导航组件 NavigationRail 的用法简介

​​Material Design 3 定义了三种导航模式&#xff0c;其用法和对应的 Flutter 组件如下所示&#xff1a; MD3 导航Flutter 组件用途Navigation barBottomNavigationBar小型屏&#xff08;宽度小于640&#xff09;Navigation drawerDrawer大型屏&#xff08;宽度大于960&…

Java基础 学习笔记四

标识符 标识符是在源代码中程序员自己有权利命名的单词标识符可以标识 变量名&#xff0c;方法名&#xff0c;类名 标识符命名规则 标识符只能由数字&#xff0c;字符&#xff08;java支持所有国家语言&#xff09;&#xff0c;_&#xff0c; $ 组成&#xff0c;不能含有其他…

基于树莓派实现 --- 智能家居

最效果展示 演示视频链接&#xff1a;基于树莓派实现的智能家居_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1Tr421n7BM/?spm_id_from333.999.0.0 &#xff08;PS&#xff1a;房屋模型的搭建是靠纸板箱和淘宝买的家居模型&#xff0c;户型参考了留学时短租的公寓~&a…

软考高级:软件测试阶段概念和例题

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《Effective Java》独家解析》专栏作者。 热门文章推荐&am…

Linux课程____进程管理

记录工作日志 script 240319.log CTRLd 退出 cat 240319.log //查看 一、查看进程 1.静态 ps -aux ps -elf 2.动态 top 3.pgrep 查看特定条件的进程 pgrep -l “log” pgrep -l "ssh" pgrep -l -U redhat 4.pstree 查看进程树 pstree -aup 所有…

Flutter 在 Windows 下的开发环境搭建(Flutter SDK 3.19.2)【图文详细教程】

Git 下载与安装 对于 Flutter 3.19&#xff0c;Git 版本需要 2.27 及以上 Git 下载&#xff1a; Git 官网&#xff1a;https://git-scm.com/Git 下载淘宝镜像&#xff1a;https://registry.npmmirror.com/binary.html?pathgit-for-windows/ 对于 Git 的安装教程&#xff0c;…

Go 1.22 - 更加强大的 Go 执行跟踪

原文&#xff1a;Michael Knyszek - 2024.03.14 runtime/trace 包含了一款强大的工具&#xff0c;用于理解和排查 Go 程序。这个功能可以生成一段时间内每个 goroutine 的执行追踪。然后&#xff0c;你可以使用 go tool trace 命令&#xff08;或者优秀的开源工具 gotraceui&a…

Unable to load host key: /etc/ssh/ssh_host_rsa_key

Unable to load host key: /etc/ssh/ssh_host_rsa_key 启动docker镜像时报错 Unable to load host key: /etc/ssh/ssh_host_rsa_key Unable to load host key: /etc/ssh/ssh_host_ecdsa_key Unable to load host key: /etc/ssh/ssh_host_ed25519_key sshd: no hostkeys availa…

多特征变量序列预测(11) 基于Pytorch的TCN-GRU预测模型

往期精彩内容&#xff1a; 时序预测&#xff1a;LSTM、ARIMA、Holt-Winters、SARIMA模型的分析与比较-CSDN博客 风速预测&#xff08;一&#xff09;数据集介绍和预处理-CSDN博客 风速预测&#xff08;二&#xff09;基于Pytorch的EMD-LSTM模型-CSDN博客 风速预测&#xff…

什么是子网掩码、ip地址的网段?如何区分?

IP地址优化网写了很多相关的文章。 有些朋友对于子网掩码、IP地址网段等还不太了解&#xff0c;我们来看看网友经常问到的一些相关问题。 255.255.255.192 的位掩码是什么&#xff1f; 1.什么是子网掩码&#xff1f; 在了解IP地址的网段之前&#xff0c;我们先来了解一下子网…

【RabbitMQ | 第四篇】基于RabbitMQ实现延迟队列

文章目录 4.基于RabbitMQ实现延迟队列4.1延迟队列定义4.2基于DLX&#xff08;死信交换机&#xff09;实现延迟队列4.2.1实现思路4.2.2主要流程4.2.3实战&#xff08;1&#xff09;创建两个消息队列&#xff1a;原始消息队列、死信队列 and 为原始消息队列关联私信交换机&#x…

高精度AI火灾烟雾检测算法,助力打造更加安全的楼宇环境

一、方案背景 近日&#xff0c;南京居民楼火灾事故导致15人死亡的新闻闹得沸沸扬扬&#xff0c;这一事件又激起了大家对楼宇火灾隐患的进一步担忧。事后我们除了思考政府、消防及物业部门应对此事的解决办法&#xff0c;我们还应该思考如何利用现有的技术帮助人们减少此类事情的…

蓝桥杯模块综合——高质量讲解AT24C02,BS18B20,BS1302,AD/DA(PCF8591),超声波模块

AT24C02——就是一个存储的东西&#xff0c;可以给他写东西&#xff0c;掉电不丢失。 void EEPROM_Write(unsigned char * EEPROM_String,unsigned char addr , unsigned char num) {IIC_Start();IIC_SendByte(0xA0);IIC_WaitAck();IIC_SendByte(addr);IIC_WaitAck();while(nu…

非正向图片如何在OCR技术层面去解决?

在OCR&#xff08;Optical Character Recognition&#xff0c;光学字符识别&#xff09;技术中&#xff0c;非正向的图片一般是指倒过来或者没有固定版式的图片&#xff0c;要识别好这类图片确实是一个挑战。这类问题通常涉及到图像预处理、特征提取和识别算法等多个环节。以下…

SpringBoot项目前端Vue访问后端(图片静态资源) 配置

静态资源配置 Configuration public class WebMvcConfig extends WebMvcConfigurationSupport {Value("${file.save-path}")private String fileSavePath;Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {//映射本地文件夹registry…