第二章:渐入佳境(下)
上回书说道,如何使用函数,声明函数;今天这篇文章将会教您如何编写自己的函数库,以及相关的小技巧。
1.头文件(xxxx.h)& C文件(xxxx.cpp/xxxx.c)
萌新可能注意到了,每次编写C语言程序的时候都要在程序的最开始加上一下代码:
#include <stdio.h>
//也许还会有
#include <stdlib.h>
#include <string.h>
这些被include关键字引用的.h文件就是头文件,形象来说就是函数们的门牌号索引,而与之对应的c/cpp文件则是函数的家。头文件的作用就是让主函数或其他引用此函数的函数能找到这个被引用的函数(有点绕)。
可以这样说,每一个被引用的c文件(c与cpp文件都是c语言文件只不过是拓展名不同)都要有一个对应的h文件。
接下来以学习文件1为例,学习一下c文件和h文件的编写:(文件压缩包放在文章底部了)
/***************这是C文件****************************/
#include "function.h"
void deltaculcu(float a, float b, float c)
{
delta = b * b - 4 * a * c;
if (delta >= 0)
{
if (delta > 0)
{
x1 = -b + sqrt(delta) / (2 * a);
x2 = -b - sqrt(delta) / (2 * a);
printf("x1=.2%f;x2=%.2f\n", x1, x2);//保留两位小数
}
else
{
x1 = -b / (2 * a);
x2 = x1;
printf("x1=x2=%.2f\n", x1);
}
}
else
{
p = -b / (2 * a);
q = sqrt(fabs(delta)) / (2 * a);
printf("x1=%.2f + %.2f i\n", p, q);//一对共轭复根
printf("x2=%.2f - %.2f i\n", p, q);
}
}
我们可以看出这个C文件只是不含有主函数main( ),我们在前面曾提到,一个程序只有一个主函数main( )。
/****************************这是h文件***********************/
#ifndef FUNCTION_H
#define FUNCTION_H
void deltaculcu(float a, float b, float c);
#endif
这个h文件很短,去掉空格就只有4行代码,关于为什么要加 #ifndef、 #define和#endif:
这是为了防止头文件被重复包含。重复包含可以用下面的例子来说明:比如有个头文件a.h,里面有个函数Fa;另一个头文件b.h,里面有函数Fb, Fb的实现需要用到Fa,则b.h中需要包含a.h;有个cpp文件中的函数需要用到Fa和Fb,则需要包含a.h和b.h,此时a.h就发生了重复包含。编译程序,出现如下错误:
error C2084: function 'bool __cdecl Fa()' already has a body
第三行的
void deltaculcu(float a, float b, float c);
//注意分号!!!!!!
是函数声明,参考上一篇文章函数声明。
2.如何编写自己的函数库
首先要确定你编写函数库的功能,根据功能来命名你的h文件和c文件。其次要确定放入函数库中的函数。
接下来演示建立函数库的流程:
- 右键左边【解决方案资源管理器】【头文件】,选择【添加】【新建项】
- 选择【头文件】,并重命名你的文件,文件名不能有中文,点击【添加】
- 在头文件中编写好框架:
#ifndef XXXXX_H
#define XXXXX_H //这里XXXXX为你的头文件名称
/***********下面写你的函数声明***************/
#endif
- 这次是在【源文件】一栏重复第一步第二步,选择【C++文件】,并重命名你的文件,文件名应与你创立的头文件一致。创建完成后,在文件中引用你的头文件:
#include "XXXXX.h" //这里通常用小写h
#include <stdio.h> //根据需要引用其他头文件
/*************下面开始编写你的函数****************/
有细心的同学会发现,在编写程序时,有些头文件是用< >括起来的,而有一些是用" "括起来的,一旦用错,将会出现以下错误:
错误 C1083 无法打开包括文件: “function.h”: No such file or directory
这二者有何区别呢,查阅VS2019官方文档错误C1803可知:使用双引号括起来的头文件,指示编译器首先应在包含源文件的同一目录中查找该文件,然后在生成环境指定的其他位置查找。 如果引号包含绝对路径,则编译器仅在该位置查找文件。 如果引号包含相对路径,则编译器在相对于源目录的目录中查找文件;而利用单书名号括起来的头文件,编译器遵循由生成环境、/I 编译器选项、/X 编译器选项和 INCLUDE 环境变量定义的搜索路径。 有关详细信息(包括有关用于查找文件的搜索顺序的特定详细信息)。
综上,为了避免出现C1803错误搞人心态,凡是自己写的头文件引用时#include后一律用双引号括起来,系统自带的头文件用单书名号括起来。
- 接下来要在主函数中调用你所写的函数:
#include <stdio.h>
#include "XXXXX.h"
int main()
{
/****************直接调用你的函数即可****************/
return 0;
}
3.编写函数库的意义
编写函数库,能够让程序更加具有条理性,可读性,可修改性。在之后的嵌入式学习中,代码量是十分恐怖的。这里以Keil5平台的stm32F103RCT6芯片驱动8×8LED点阵模块程序为例:
这么多代码不分类创建函数库,维护或者修改程序时怕不是要累死(坏笑.jpg),当然了你要是想坑你队友我还是很推荐你把所有程序都堆主函数main里面的,不过你能不能见到明天的太阳就不一定了(再次坏笑.jpg)在这个简单的嵌入式项目里,每个文件都各司其职,稳定且高效率的发挥着自己的作用。
另外,除了以上的作用之外,编写函数库还能增加程序的可移植性,很多时候,嵌入式平台的芯片之间,配置文件并不通用(比如英飞凌公司的TC系列芯片和意法半导体公司的ST芯片编程平台都不一样),但有些外接设备是一样的,这时如果没有函数库,就只能重新编写相应的程序,但比如LCD屏幕外设的程序有上千行,自己编写肯定不现实,这时函数库函数文件便于移植的特性就完美显现。
总之,会编写自己的函数库(也叫模块化编程)是一项最重要也最基本的功能,是C语言初学者必须掌握的技能。
本期所用到的程序:学习资料1
提取码:1017
下一期预告:数组与指针与函数的激♂情碰撞(上)