51单片机入门 - 测试:SDCC / Keil C51 会让没有调用的函数参与编译吗?
Small Device C Compiler(SDCC)是一款免费 C 编译器,适用于 8 位微控制器。
不想看测试过程的话可以直接划到最下面看结论:)
关于软硬件环境的信息:
- Windows 10
- STC89C52RC
- SDCC (构建HEX文件)
- stcgal 1.6 (向STC单片机烧录)
修改代码中的数值会改变编译后的结果
显然,在我们修改一些 C 语言代码的时候,编译后的二进制文件也可能发生改变,尤其是一些关键的数值,在 51 单片机开发中,C 代码会编译成 .HEX 文件,然后烧录到单片机。
下面用 SDCC 编译这个示例程序来演示:
- 这是个选择一位数码管并使其亮起的程序:
#include <8051.h>#define decoder_in_1 P2_2 // 译码器的 3 位输入,用于位选 #define decoder_in_2 P2_3 #define decoder_in_3 P2_4 #define NUMBER P0unsigned int LED_MAP[11] = {0x3f, 0x6, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x7, 0x7f, 0x6f};void send_to_decoder(unsigned int position) { // position: 1 ~ 8 position--; // position: 0 ~ 7 (000 ~ 111)decoder_in_1 = position & 1; // low bit of position (position & 001)decoder_in_2 = position & 2; // middle bit of position (position & 010)decoder_in_3 = position & 4; // high bit of position (position & 100) }void main() {send_to_decoder(1); // 位选:选择第 1 位数码管亮起NUMBER = LED_MAP[6]; // 段选:数码管显示数字 6 } - 改变了上面代码的位选,选择第 2 位数码管亮起:
#include <8051.h>#define decoder_in_1 P2_2 // 译码器的 3 位输入,用于位选 #define decoder_in_2 P2_3 #define decoder_in_3 P2_4 #define NUMBER P0unsigned int LED_MAP[11] = {0x3f, 0x6, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x7, 0x7f, 0x6f};void send_to_decoder(unsigned int position) { // position: 1 ~ 8 position--; // position: 0 ~ 7 (000 ~ 111)decoder_in_1 = position & 1; // low bit of position (position & 001)decoder_in_2 = position & 2; // middle bit of position (position & 010)decoder_in_3 = position & 4; // high bit of position (position & 100) }void main() {send_to_decoder(2); // 位选:选择第 2 位数码管亮起NUMBER = LED_MAP[6]; // 段选:数码管显示数字 6 }
对比它们生成的 HEX 文件的区别:
slightwind@ubuntu:/xxx/diff$ diff 1.hex 2.hex
9c9
< :0C00BE00A42290000112009E85148022F4
---
> :0C00BE00A42290000212009E85148022F3
可以看到第 9 行出现了区别。
头文件中没有被调用的函数
把数组 LED_MAP 放到头文件中,再从主函数中调用,头文件还包含了程序没有调用过的 sleep()。
swutil.h:
#ifndef __SWUTIL_H__
#define __SWUTIL_H__unsigned int LED_MAP[11] = {0x3f, 0x6, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x7, 0x7f, 0x6f};void sleep(unsigned int n); // sleep n (ms)#endif
swutil.c:
void sleep(unsigned int n){unsigned char i, j;while (n--){i = 2;j = 239;do{while(--j);}while(--i);}
}
main.c:
#include <8051.h>
#include "swutil.h"#define decoder_in_1 P2_2 // 译码器的 3 位输入,用于位选
#define decoder_in_2 P2_3
#define decoder_in_3 P2_4
#define NUMBER P0void send_to_decoder(unsigned int position) { // position: 1 ~ 8 position--; // position: 0 ~ 7 (000 ~ 111)decoder_in_1 = position & 1; // low bit of position (position & 001)decoder_in_2 = position & 2; // middle bit of position (position & 010)decoder_in_3 = position & 4; // high bit of position (position & 100)
}void main() {send_to_decoder(1); // 位选:选择第 1 位数码管亮起NUMBER = LED_MAP[6]; // 段选:数码管显示数字 6
}
这时使用 SDCC 编译后生成的 HEX 文件和前面第一个实例代码生成的 HEX 文件完全一致,说明没有额外的函数参与了编译,也就是说尽管导入了比较复杂的头文件,编译器也只会让调用过的函数参与编译。
主文件中没有调用的函数
下面这个程序在前面第一个实例代码的基础上额外定义了 sleep() 函数,但是没有调用:
#include <8051.h>#define decoder_in_1 P2_2 // 译码器的 3 位输入,用于位选
#define decoder_in_2 P2_3
#define decoder_in_3 P2_4
#define NUMBER P0unsigned int LED_MAP[11] = {0x3f, 0x6, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x7, 0x7f, 0x6f};void send_to_decoder(unsigned int position) { // position: 1 ~ 8 position--; // position: 0 ~ 7 (000 ~ 111)decoder_in_1 = position & 1; // low bit of position (position & 001)decoder_in_2 = position & 2; // middle bit of position (position & 010)decoder_in_3 = position & 4; // high bit of position (position & 100)
}void sleep(unsigned int n){unsigned char i, j;while (n--){i = 2;j = 239;do{while(--j);}while(--i);}
}void main() {send_to_decoder(1); // 位选:选择第 1 位数码管亮起NUMBER = LED_MAP[6]; // 段选:数码管显示数字 6
}
同样是用 SDCC 编译,diff 一下和第一个程序生成的 HEX 的区别,可以发现文件变大了,也有很多不一样的地方。
slightwind@ubuntu:/xxx/diff$ diff 1.hex 4.hex
6c6
< :030003000200C038
---
> :030003000200DC1C
9c9,11
< :0C00BE00A42290000112009E85148022F4
---
> :1000BE00A422AE82AF838E048F051EBEFF011FECFD
> :1000CE004D600A7DEF7C02DDFEDCFC80E9229000B3
> :0800DE000112009E851480222E
11c13
< :100013007900E94400601B7A009000CE780175A056
---
> :100013007900E94400601B7A009000EA780175A03A
17,18c19,20
< :0D00060075811D1200CAE58260030200032F
< :0400CA007582002219
---
> :0D00060075811D1200E6E582600302000313
> :0400E60075820022FD
所以在 main.c 中定义的函数,即使没有调用,也会参与 HEX 文件的构建。
在Keil_C51编译器上的测试
另外,我还将编译器换成了 Keil_C51 进行了一遍上述的测试,发现不管是包含的头文件中的函数,还是 main.c 中定义的函数,只要没有调用,都不会参与到编译中1,这样有利于生成更小的 HEX 文件。
结论
在 SDCC 中,使用的头文件中声明的函数,没有调用的话是不会参与编译的,但是在 main.c 里面直接定义的函数,尽管没有调用也是会参与编译的。
以这个简单的例子看来,在编译优化方面还是 Keil 做的更专业一些,不过 SDCC 胜在免费,是不想使用付费/破解软件时的一个不错的替代品。
这只是从上面这个简单的示例程序中表现出来的现象得到的结论,编译器的实现和优化工作非常复杂,在其他情况下可能表现出不同的结果。 ↩︎
相关文章:
51单片机入门 - 测试:SDCC / Keil C51 会让没有调用的函数参与编译吗?
Small Device C Compiler(SDCC)是一款免费 C 编译器,适用于 8 位微控制器。 不想看测试过程的话可以直接划到最下面看结论:) 关于软硬件环境的信息: Windows 10STC89C52RCSDCC (构建HEX文件&…...
【计算机网络】计算机网络
目录一、概述计算机网络体系结构二、应用层DNS应用文件传输应用DHCP 应用电子邮件应用Web应用当访问一个网页的时候,都会发生什么三、传输层UDP 和 TCP 的特点UDP 首部格式TCP 首部格式TCP 的三次握手TCP 的四次挥手TCP 流量控制TCP 拥塞控制三、网络层IP 数据报格式…...
【java web篇】项目管理构建工具Maven简介以及安装配置
📋 个人简介 💖 作者简介:大家好,我是阿牛,全栈领域优质创作者。😜📝 个人主页:馆主阿牛🔥🎉 支持我:点赞👍收藏⭐️留言Ὅ…...
springboot笔记
微服务架构 微服务是一种架构风格,开发构建应用的时候把应用的业务构建成一个个的小服务(这就类似于把我们的应用程序构建成了一个个小小的盒子,它们在一个大的容器中运行,这种一个个的小盒子我们把它叫做服务)&#…...
【多线程与高并发】- 浅谈volatile
浅谈volatile简介JMM概述volatile的特性1、可见性举个例子总结2、无法保证原子性举个例子分析使用volatile对原子性测试使用锁的机制总结3、禁止指令重排什么是指令重排序重排序怎么提高执行速度重排序的问题所在volatile禁止指令重排序内存屏障(Memory Barrier)作用volatile内…...
avro格式详解
【Avro介绍】Apache Avro是hadoop中的一个子项目,也是一个数据序列化系统,其数据最终以二进制格式,采用行式存储的方式进行存储。Avro提供了:丰富的数据结构可压缩、快速的二进制数据格式一个用来存储持久化数据的容器文件远程过程…...
【涨薪技术】0到1学会性能测试 —— LR录制回放事务检查点
前言 上一次推文我们分享了性能测试分类和应用领域,今天带大家学习性能测试工作原理、事务、检查点!后续文章都会系统分享干货,带大家从0到1学会性能测试,另外还有教程等同步资料,文末免费获取~ 01、LR工作原理 通常…...
卡尔曼滤波原理及代码实战
目录简介1.原理介绍场景假设(1).下一时刻的状态(2).增加系统的内部控制(3).考虑运动系统外部的影响(4).后验估计:预测结果与观测结果的融合卡尔曼增益K2.卡尔曼滤波计算过程(1).预测阶段(先验估计阶段)(2).更新阶段(后验估计阶段&…...
Jmeter使用教程
目录一,简介二,Jmeter安装1,下载2,安装三,创建测试1,创建线程组2,创建HTTP请求默认值3,创建HTTP请求4,添加HTTP请求头5,添加断言6,添加查看结果树…...
论文笔记|固定效应的解释和使用
DeHaan E. Using and interpreting fixed effects models[J]. Available at SSRN 3699777, 2021. 虽然固定效应在金融经济学研究中无处不在,但许多研究人员对作用的了解有限。这篇论文解释了固定效应如何消除遗漏变量偏差并影响标准误差,并讨论了使用固…...
数据集市与数据仓库的区别
数据仓库是企业级的,能为整个企业各个部门的运作提供决策支持;而数据集市则是部门级的,一般只能为某个局部范围内的管理人员服务,因此也称之为部门级数据仓库。 1、两种数据集市结构 数据集市按数据的来源分为以下两种 &#x…...
Golang学习Day3
😋 大家好,我是YAy_17,是一枚爱好网安的小白。 本人水平有限,欢迎各位师傅指点,欢迎关注 😁,一起学习 💗 ,一起进步 ⭐ 。 ⭐ 此后如竟没有炬火,我便是唯一的…...
Python并发编程-事件驱动模型
一、事件驱动模型介绍 1、传统的编程模式 例如:线性模式大致流程 开始--->代码块A--->代码块B--->代码块C--->代码块D--->......---&…...
构建系统发育树简述
1. 要点 系统发育树代表了关于一组生物之间的进化关系的假设。可以使用物种或其他群体的形态学(体型)、生化、行为或分子特征来构建系统发育树。在构建树时,我们根据共享的派生特征(不同于该组祖先的特征)将物种组织成…...
这款 Python 调试神器推荐收藏
大家好,对于每个程序开发者来说,调试几乎是必备技能。 代码写到一半卡住了,不知道这个函数执行完的返回结果是怎样的?调试一下看看 代码运行到一半报错了,什么情况?怎么跟预期的不一样?调试一…...
金三银四吃透这份微服务笔记,面试保准涨10K+
很多人对于微服务技术也都有着一些疑虑,比如: 微服务这技术虽然面试的时候总有人提,但作为一个开发,是不是和我关系不大?那不都是架构师的事吗?微服务不都是大厂在玩吗?我们这个业务体量用得着…...
构建matter over Thread的演示系统-efr32
文章目录1. 简介2. 构建测试系统2.1设置 Matter Hub(Raspberry Pi)2.2 烧录Open Thread RCP固件2.3 烧录待测试的matter设备3. 配网和测试:3.1 使用mattertool建立Thread网络3.2 使用mattertool配置设备入网3.3 使用mattertool控制matter设备3.4 查看节点的Node ID等…...
【一天一门编程语言】Matlab 语言程序设计极简教程
Matlab 语言程序设计极简教程 用 markdown 格式输出答案。 不少于3000字。细分到2级目录。 目录 Matlab 语言程序设计极简教程 简介Matlab 工作空间Matlab 基本数据类型Matlab 语句和表达式Matlab 函数和程序Matlab 图形界面程序设计Matlab 应用实例 简介 Matlab是一种编…...
看似平平无奇的00后,居然一跃上岸字节,表示真的卷不过......
又到了一年一度的求职旺季金!三!银!四!在找工作的时候都必须要经历面试这个环节。在这里我想分享一下自己上岸字节的面试经验,过程还挺曲折的,但是还好成功上岸了。大家可以参考一下! 0821测评 …...
BZOJ2142 礼物
题目描述 一年一度的圣诞节快要来到了。每年的圣诞节小E都会收到许多礼物,当然他也会送出许多礼物。不同的人物在小E 心目中的重要性不同,在小E心中分量越重的人,收到的礼物会越多。小E从商店中购买了n件礼物,打算送给m个人 &…...
4G DTU选型指南:Cat1模块在智能水电表项目中的7个关键参数对比
4G DTU选型实战:Cat1模块在智能水电表项目中的7个工程化参数解析 水电表远程抄表系统正经历从2G向4G Cat1的技术迁移浪潮。作为工业现场的核心通信枢纽,DTU模块的选型直接关系到数据上报成功率、设备维护成本和系统生命周期。本文将基于某省级电网改造项…...
避开这5个坑!用MediaRecorder+Vue3实现高兼容性语音输入
Vue3MediaRecorder实战:5个关键技巧打造高兼容语音输入方案 在移动优先的时代,语音输入已成为提升用户体验的重要交互方式。但当你兴奋地在Vue3项目中集成MediaRecorder API时,可能会遇到iOS设备上的静默失败、Android机型上的格式兼容性问题…...
实战应用:使用快马平台为vmware17部署生成企业级健康检查与配置方案
在实际的企业IT环境中,部署VMware vSphere 17(以下简称VMware 17)这类虚拟化平台往往不是简单的安装过程,而是需要综合考虑硬件兼容性、系统配置、安全策略等多方面因素。为了确保部署过程的顺利和后续运行的稳定,我们…...
NSSCTF做题记录九 | [HUBUCTF 2022 新生赛]checkin
[HUBUCTF 2022 新生赛]checkin <?php show_source(__FILE__); //高亮显示当前代码 $username "this_is_secret"; //给$username赋值 $password "this_is_not_known_to_you"; //给$password赋值 include("flag.php");//here I chan…...
基于Spark+Hadoop+Hive 深度学习大数据的运河航运效率提升平台的设计与实现
前言随着全球贸易的不断发展,运河航运作为连接内陆与海洋的重要交通方式,其运输效率的提升对于促进经济发展、优化资源配置具有重要意义。基于大数据的运河航运效率提升平台的设计与实现,旨在通过收集、处理和分析大量的航运数据,…...
Ubuntu 18.04 + CUDA 11.3 下,手把手教你搞定 MinkowskiEngine 的编译安装(附避坑指南)
Ubuntu 18.04 CUDA 11.3 环境下的 MinkowskiEngine 编译实战指南 在3D点云处理和稀疏卷积领域,MinkowskiEngine 凭借其高效的稀疏张量计算能力已成为研究者的重要工具。然而,其复杂的依赖关系和编译过程常常让开发者望而却步。本文将基于 Ubuntu 18.04…...
别再折腾官方源了!用XianDian-IaaS-v2.2在CentOS7上30分钟搞定OpenStack最小化部署
30分钟极速部署OpenStack:XianDian-IaaS在CentOS7上的实战指南 OpenStack作为开源云计算平台的标杆,其强大的灵活性和模块化设计吸引了大量企业用户。但官方部署流程的复杂性往往让初学者望而却步——依赖项冲突、版本兼容性问题、繁琐的配置步骤&#x…...
微信小程序语音交互实战:长按录制与点击播放的完整实现方案
1. 微信小程序语音交互功能概述 语音交互已经成为现代移动应用不可或缺的功能之一。在微信小程序中实现语音录制与播放,能够极大提升用户体验,特别适合社交、教育、工具类小程序。我最近在一个社交类小程序项目中实现了完整的语音交互模块,踩…...
PFC(5.0)模拟:GBM模型(grain- based model ) pb-sj或pb-...
PFC(5.0)模拟:GBM模型(grain- based model ) pb-sj或pb-pb 单轴压缩。 模拟花岗岩等矿物晶体岩石,多种矿物晶体模型,其中矿物种类 数量分布可以自定义。 可以监测sj裂纹,和各矿物内裂纹。PFC5.0的GBM模型玩岩石破裂是真…...
如何用Obsidian Image Converter实现图像高效管理?超实用技巧分享
如何用Obsidian Image Converter实现图像高效管理?超实用技巧分享 【免费下载链接】obsidian-image-converter ⚡️ Convert, compress, resize, annotate, markup, draw, crop, rotate, flip, align images directly in Obsidian. Drag-resize, rename with variab…...
