打印
[ARM入门]

在C语言固件中使用功能的五个技巧

[复制链接]
395|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
潜力变实力|  楼主 | 2020-9-15 10:14 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在本文中,我们将通过一些附加信息和一些有用的实现技术来结束对C函数的探索。
基本的C函数(例如,一个或两个参数和一个返回值)并不复杂。但是,C函数非常灵活,通过超越基础知识,您可以更轻松地编写代码,并将一些有益的特性引入固件。

1.将函数原型放入头文件中

有时我想知道一个人是否必须是计算机科学专业才能完全理解C语言功能原型。这确实是一个相当复杂的问题。我认为固件工程师可以放心地忽略这些细节,而只需采取以下标准操作:始终为您的功能提供一个原型,并将这些原型放置在头文件中。

函数原型是一行代码,为编译器提供函数自变量和返回值的数据类型。例如:
float ArithmeticMean(char Value1,char Value2,char Value3);
复制代码
实际上,不必包含输入参数的名称,因为此时编译器希望知道的只是数据类型。因此,您也可以按如下方式编写原型:
float ArithmeticMean(char,char,char);
复制代码
我更喜欢包含参数名称,这可能是因为它允许我通过从函数定义中复制和粘贴来创建函数原型。
当函数原型被遗漏或放错位置时,可能会发生奇怪的事情,而根据我的经验,消除这些问题的最简单方法是将所有函数原型放置在项目的所有源文件中包含的头文件中。这样可以确保您可以安全地在任何源文件中使用任何函数,因为在调用每个函数之前,总是会对其进行声明(即,在头文件中)。

例如,以下代码段摘自一个名为“ Project_DefsVarsFuncs.h”的文件。
//function prototypes
void Delay_us(unsigned int DelayCount);
void Delay_10ms(unsigned int DelayCount);
void Delay_seconds(unsigned int DelayCount);
void Update_LCD(unsigned char SensorNumber, unsigned long displayValue);
void LCD_Clear_All();
复制代码
此头文件包含在我的源文件中,如下所示:
//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include "Project_DefsVarsFuncs.h"
复制代码
2.将函数声明为静态以避免命名冲突
随着固件项目变得越来越大和越来越复杂,您可能会发现要在不同的源文件中重用相同的功能名称。您可以使用“ static”关键字来完成此操作。如上所述,在这种情况下,您不会将函数原型放置在头文件中。
“ static”关键字将功能范围限制为一个源文件。这使您可以对不同源文件中的不同功能使用相同的功能名称。在下面显示的示例中,该项目需要三个不同的ProcessData()函数-一个用于分析ADC数据,一个用于响应UART命令,另一个用于处理I 2 C消息。



我将“ static”关键字放在函数原型的前面,然后函数原型移到源文件的顶部(即,在由函数体内的处理器指令组成的“正常”代码之前)。
当多个工程师将要从事同一固件项目时,“ static”关键字也很方便。如果两个工程师正在不同的源文件中工作,则使用静态功能可以使工程师A选择功能名称,而不必担心工程师B将为不同功能选择相同名称的可能性。

3.使用指针将数组传递给函数
嵌入式应用程序经常使用数组-传感器读数,ADC值,短ASCII消息等序列。在这种开发环境中,函数似乎有点尴尬,因为您无法将数组传递给C函数。确实,您不能像传递单个变量那样传递数组,但是可以使用指针为函数提供对数组数据的访问权限。
如果将指针作为参数之一,然后在调用函数时传递数组标识符,则函数主体中的语句可以使用该指针读取和修改数组的内容。如果您对此概念感到有些困惑,建议您先阅读有关C语言中数组的** ,然后阅读有关指针的第一篇**。

4.您可以使用指针调用函数
指针是保存内存地址的变量。该地址通常标识变量或数组第零个元素的位置。但是,指针也可以指向函数。



如果您已经阅读了有关C函数的第一篇**,您就会知道函数存储在代码存储器的特定位置,就像变量存储在数据存储器的特定位置一样。如果存储在指针中的值是函数的起始地址,则可以使用指针来调用该函数。如果更改指针的值使其等于不同函数的起始地址,则可以使用同一指针来调用该不同函数。
以下代码段显示了如何声明可与具有三个char参数和返回类型float的函数一起使用的函数指针。
float(* Ptr_to_Function)(char,char,char);
复制代码
数组标识符本质上是指向数组第零个元素的指针。同样,功能名称被解释为功能的起始地址(在代码存储器中)。因此,可以将函数分配给函数指针,如下所示:
Ptr_to_Function = ArithmeticMean;
复制代码
现在,您可以使用Ptr_to_Function调用函数ArithmeticMean()。以下两个语句是等效的:
Average = ArithmeticMean(Temperature1, Temperature2, Temperature3);

Average = (*Ptr_to_Function)(Temperature1, Temperature2, Temperature3);
复制代码
5.尽可能使用局部变量
我认为,在许多情况下,我们的本能是在源文件的顶部定义所有变量,然后将其保留在该位置。但是,养成在函数中使用局部变量的习惯是很好的。局部变量的范围仅限于定义它的功能。换句话说,变量是在调用函数时创建的,并在函数完成其任务后消失。
我推荐局部变量有两个原因。首先,它们允许您在不同的函数中重用相同的变量名。复杂的项目可能包含许多需要基本变量的功能,例如循环计数器。我喜欢对循环计数器重复使用“ n”,而不是逐步遍历字母表中的所有字母。
其次,使用局部变量可能会导致更快的代码。我不是编译器专家,但是我认为局部变量很可能放在寄存器中而不是存储位置,并且访问寄存器要比访问内存快。


寄存器是处理器的组成部分,可以快速读取和写入数据。
结论
我们在这里讨论了很多与C语言中函数使用有关的细节,并且我希望这些信息可以帮助您提高固件的效率和功能(无双关)。如果您有任何与功能相关的技巧,请随时在下面的评论部分中分享。

使用特权

评论回复

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

211

主题

1124

帖子

9

粉丝