我正在使用C。
开发嵌入式程序有很多硬件宏,比如
#ifdef HardwareA
do A
#endif
它不可读,并且难以用单元测试覆盖所有不同的路径。
因此,我决定将硬件相关代码移动到arch文件夹,并使用makefile中的宏来决定链接哪个arch文件夹。就像Linux内核代码一样。
但是当我看到Linux内核时,我注意到arch文件夹中有很多重复项。
如果在一个硬件中发现错误,它们如何对所有相关硬件进行更改,但可能会影响所有其他硬件?
我认为这样做不可避免地会给代码库带来重复。
有没有人有这类问题的经验?
如何对包含大量硬件宏的代码进行单元测试?
重构代码以将硬件宏移离源代码?
答案 0 :(得分:3)
听起来你正在替换这样的函数:
somefunc()
{
/* generic code ... */
#ifdef HardwareA
do A
#endif
/* more generic code ... */
}
有多个实现,每个arch文件夹中有一个,如下所示:
somefunc()
{
/* generic code ... */
/* more generic code ... */
}
somefunc()
{
/* generic code ... */
do A
/* more generic code ... */
}
通用代码的重复是您所担心的。不要这样做:相反,有一个函数的实现,如下所示:
somefunc()
{
/* generic code ... */
do_A();
/* more generic code ... */
}
..然后在arch文件夹中实现do_A()
:在硬件A上它具有该硬件的代码,而在其他硬件上,它是一个空函数。
不要害怕空函数 - 如果你在arch头文件中定义inline
函数,它们将被完全优化。
答案 1 :(得分:2)
Linux试图避免在多个arch目录之间复制代码。您将看到实现了相同的功能,但实现了不同。毕竟,所有体系结构都需要用于管理页表的代码,但细节不同。所以他们都有相同的功能,但定义不同。
对于某些函数,构建系统定义CONFIG_GENERIC_*
,用泛型版本替换不必要的架构钩子(通常是无操作)。例如,没有FPU的拱门不需要挂钩来保存/恢复上下文切换时的FPU状态。
答案 2 :(得分:1)
这种#ifdef
地狱肯定是要避免的,但自然你也想避免代码重复。我并不认为这会解决您的所有问题,但我认为您可以将#ifdef
从#ifdef HardwareX
更改为#ifdef HAVE_FeatureY
或#ifdef USE_FeatureZ
,这是最重要的一步。这允许您做的是考虑哪些硬件/ OS /等的知识。目标具有所有源文件中的哪些功能/接口以及单个标头,这可以避免以下情况:
#if defined(HardwareA) || (defined(HardwareB) && HardwareB_VersionMajor>4 || ...
渲染您的来源不可读。
答案 3 :(得分:1)
我倾向于将特定于硬件的#defines移动到每个平台的一个标头中,然后在“platform.h”文件中选择它,所有源文件都包含在该文件中。
platform.h:
#if defined PLATFORM_X86_32BIT
#include "Platform_X86_32Bit.h"
#elsif defined PLATFORM_TI_2812
#include "Platform_TI_2812.h"
#else
#error "Project File must define a platform"
#endif
特定于体系结构的标头将包含两件事。
1)所有常见整数大小的Typedef,如typedef short int16_t;
请注意,c99指定了具有这些预定义的'stdint.h'。 (切勿在便携式代码中使用原始int
。)
2)所有硬件特定行为的函数头或宏。通过提取函数的所有依赖关系,代码的主体仍然是干净的:
//example data receive function
HW_ReceiverPrepare();
HW_ReceiveBytes(buffer, bytesToFetch);
isGood = (Checksum(buffer+1, bytesToFetch-1) == buffer[0])
HW_ReceiverReset();
然后,一个特定于平台的标题可以将原型提供给复杂的HW_ReceiverPrepare()
函数,而另一个标题只是用#define HW_ReceiverPrepare()
这在您的评论中描述的情况下非常有效,其中平台之间的差异通常是一行或两行。只需将这些行封装为函数/宏调用,就可以保持代码的可读性,同时最大限度地减少重复。