当前位置: 首页 > news >正文

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 编译这个示例程序来演示:

  1. 这是个选择一位数码管并使其亮起的程序:
    #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. 改变了上面代码的位选,选择第 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 胜在免费,是不想使用付费/破解软件时的一个不错的替代品。


  1. 这只是从上面这个简单的示例程序中表现出来的现象得到的结论,编译器的实现和优化工作非常复杂,在其他情况下可能表现出不同的结果。 ↩︎

http://www.lryc.cn/news/19219.html

相关文章:

  • OpenCV只含基本图像模块编译
  • Java实现阴历日历表(附带星座)
  • Python入门之最基础
  • 浏览器缓存策略
  • 高清无码的MP4如何采集?python带你保存~
  • python+pytest接口自动化(1)-接口测试基础
  • go单元测试
  • Mybatis之一级缓存二级缓存
  • 人脸考勤机项目
  • Python编程自动化办公案例(3)
  • Linux-MYSQL 登录数据库(命令行,图形化) 及 远程登录
  • electron网络环境在线/离线事件探测
  • UE 项目导航数据生成配置
  • 494.目标和
  • 滑台模组的应用有哪些?
  • CS224W课程学习笔记(四):node2vec算法原理与说明
  • 扩展lucas定理
  • 医疗影像工具LEADTOOLS 入门教程: 从 PDF 中提取附件 - 控制台 C#
  • 【LVGL】学习笔记--(1)Keil中嵌入式系统移植LVGL
  • Transformer学习笔记
  • vue-cli引入wangEditor、Element,封装可上传附件的富文本编辑器组件(附源代码直接应用,菜单可调整)
  • 移动办公时代,数智化平台如何赋能企业管理升级?
  • 2023“拼夕夕”为什么可以凭借简单的拼团做这么大?
  • sqlmap工具
  • 高/低压供配电系统设计——安科瑞变电站电力监控系统的应用
  • Tapdata 和 Databend 数仓数据同步实战
  • 单核CPU, 1G内存,也能做JVM调优吗?
  • 《计算机应用研究》投稿经历和时间节点
  • mars3d获取视窗的范围
  • 《高性能MySQL》读书笔记(上)