51单片机入门 - SDCC / Keil_C51 会让没有调用的函数参与编译吗?
Posted 风好衣轻
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 P0 unsigned 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 P0 unsigned 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 P0
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
这时使用 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 P0
unsigned 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 会让没有调用的函数参与编译吗?的主要内容,如果未能解决你的问题,请参考以下文章
Proteus仿真51单片机基于SDCC编译器对程序编译和仿真全过程讲解
单片机成长之路(51基础篇) - 009 关于sdcc的多文件编译范例