2011-08-23 70 views
1

我正在用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 ... */ 
} 

有多種實現,一個在每個拱文件夾,例如:

somefunc() 
{ 
    /* generic code ... */ 

    /* more generic code ... */ 
} 

somefunc() 
{ 
    /* generic code ... */ 

    do A 

    /* more generic code ... */ 
} 

的通用代碼的重複是什麼你擔心。不要做:代替,有一個實現的功能是這樣的:

somefunc() 
{ 
    /* generic code ... */ 

    do_A(); 

    /* more generic code ... */ 
} 

..和然後實現在拱文件夾do_A():在硬件上它具有硬件的代碼,並在其他硬件,它是一個空的功能。

不要害怕空功能 - 如果你使它們在拱頭文件中定義的功能inline,它們將被完全優化。

+0

是的,這就是我所關心的。 –

2

Linux試圖避免在多個arch目錄之間重複的代碼。你會看到相同的功能實施,但實施不同。畢竟,所有體系結構都需要用於管理頁表的代碼,但細節有所不同。所以它們都具有相同的功能,但具有不同的定義。

對於某些功能,有構建系統定義的CONFIG_GENERIC_*,這些構建系統也會使用通用版本替換不必要的體系結構鉤子(通常是no-ops)。例如,沒有FPU的拱形不需要掛鉤來保存/恢復上下文切換時的FPU狀態。

+0

我面對的問題與Linux內核有點不同,通用代碼占主導地位,與硬件相關的代碼更少,在硬件A中,僅添加一行代碼,用於另一硬件B,兩行代碼,因此,它真的我很難從中提取一些常見的界面或功能,並將它們放在拱形文件夾中,您覺得如何? –

1

這種#ifdef地獄肯定是要避免的,但自然你也想避免代碼重複。我不認爲這將解決你所有的問題,但我認爲最大的一步可以讓你將#ifdef#ifdef HardwareX改爲#ifdef HAVE_FeatureY#ifdef USE_FeatureZ。這可以讓你做什麼是因素的知識,哪些硬件/操作系統/等。目標有哪些功能/界面你的所有源文件和成一個頭,從而避免了諸如:

#if defined(HardwareA) || (defined(HardwareB) && HardwareB_VersionMajor>4 || ... 

渲染你的源代碼不可讀。

+0

我不明白,使用功能而不是硬件,仍然需要ifdef來決定打開或關閉哪些代碼,你的意思是我們可以將它們移動到某個頭文件?怎麼做?謝謝。 –

1

我傾向於將特定於硬件的#define移動到每個平臺的一個頭文件中,然後在所有源文件包含的「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()

定義它遠在您的評論中描述的情況下,這種情況非常有效,其中平臺之間的差異通常爲一行或兩行。只需將這些行封裝爲函數/宏調用,並且可以保持代碼可讀性,同時最大限度地減少重複。