2010-05-12 40 views
2

在我正在開發的嵌入式系統中,我們使用了一個函數指針表來支持專有的動態庫。將函數指針表的索引同步到表內容

我們有一個使用命名常量(#define)作爲函數指針索引的頭文件。這些值用於計算函數地址表中的位置。

實施例:

(export_table.c)

// Assume each function in the table has an associated declaration 
typedef void (*Function_Ptr)(void); 

Function_Ptr Export_Function_Table[] = 
{ 
    0, 
    Print, 
    Read, 
    Write, 
    Process, 
}; 

這裏是頭文件:
export_table.h

#define ID_PRINT_FUNCTION 1 
#define ID_READ_FUNCTION 2 
#define ID_WRITE_FUNCTION 3 
#define ID_PROCESS_FUNCTION 4 

我正在尋找爲一個方案根據它們在數組中的位置來定義命名常量,以便當函數的順序改變時,常量也將改變。
(另外,我想編譯器或預處理器來計算指數,以避免人爲錯誤,類似於類型0的。)

+1

問CW問題並不鼓勵人們迴應。 – 2010-05-12 21:12:04

回答

1

不是數組,你可以定義每個函數指針命名元素的結構:

struct call_table { 
    Function_Ptr reserved;  
    Function_Ptr print_fcn;  
    Function_Ptr read_fcn;  
    Function_Ptr write_fcn;  
    Function_Ptr process_fcn;  
}; 
+0

不幸的是,這將是一個好主意,表格在遺留代碼中。改變可能意味着向所有參與者解釋一切。 – 2010-05-13 22:10:39

1

我的建議是:不要直接使用C.從作爲構建過程一部分的本地定義的DSL中編寫的輸入文件生成.c和.h文件。然後,您只有一個源文件來維護(寫入您的DSL),並且DSL編譯器確保導出的索引與陣列的實現相匹配。

我們在這裏使用這種技術。該DSL基本上是一個帶註釋的C文件看起來是這樣的:

@@generate .h 
#ifndef __HEADER_H 
#define __HEADER_H 

@export FN_LIST 

#endif 
@@generate .c 
#include "foo.h" 

@define FN_LIST 
int myArray[] = 
{ 
    @FN_INDEX_FOO 
    12, 
    @FN_INDEX_BAR 
    13, 
    @FN_INDEX_BAZ 
    14, 
} 

這將產生一個foo.h,看起來像:

#ifndef __HEADER_H 
#define __HEADER_H 

#define FN_INDEX_FOO 0 
#define FN_INDEX_BAR 1 
#define FN_INDEX_BAZ 2 

#endif 

foo.c,看起來像:

#include "foo.h" 

int myArray[] = 
{ 
    /* FN_INDEX_FOO = 0 */ 
    12, 
    /* FN_INDEX_BAR = 1 */ 
    13, 
    /* FN_INDEX_BAZ = 2 */ 
    14, 
} 

解析器具有一些計算大括號嵌套和逗號以計算C數組中每個元素的索引的能力。

+0

這是應用於現有(遺留)代碼的大量工作。我相信這是一個更好的解決方案,但維護率很高(不僅代碼需要維護,但語言和工具必須記錄和維護,我不能在當前時間表中證明這一點)。 – 2010-05-13 22:14:28

0

X宏可以提供幫助。例如,創建一個新的文件export_table_x.h,包含:

X_MACRO(Print), 
X_MACRO(Read), 
X_MACRO(Write), 
X_MACRO(Process) 

然後在你的export_table.h,使用方法:

#define X_MACRO(x) ID_ ## x ## _FUNCTION 
enum 
{ 
    ID_INVALID = 0, 
    #include "export_table_x.h" 
}; 
#undef X_MACRO 

而且在export_table。C,寫:

#include "export_table.h" 

// ... 

#define X_MACRO(x) x 
Function_Ptr Export_Function_Table[] = 
{ 
    0, 
    #include "export_table_x.h" 
}; 

一個改變你原來的功能是ID_PRINT_FUNCTION現在ID_Print_FUNCTION等

無需添加額外的文件很討厭,但你可以通過使用的#ifdef,並把避免這種原始頭文件中的所有內容儘管不太清楚。

3

使用C99,您可以使用指定的初始化:

enum { 
    ID_PRINT_FUNCTION = 1, 
    ID_READ_FUNCTION = 2, 
    ID_WRITE_FUNCTION = 3, 
    ID_PROCESS_FUNCTION = 4, 
}; 

(後面的逗號是允許在C99,技術上,它不是在C90)。

// Assume each function in the table has an associated declaration 
typedef void (*Function_Ptr)(void); 

Function_Ptr Export_Function_Table[] = 
{ 
    [ID_READ_FUNCTION] = Read, 
    [ID_WRITE_FUNCTION] = Write, 
    [ID_PROCESS_FUNCTION] = Process, 
    [ID_PRINT_FUNCTION] = Print, 
}; 

注意,我特意重新排序那 - 編譯器將其排序。此外,雖然我將'#define'值重寫爲'枚舉'值,但它可以與任何一個配合使用。

請注意,Windows上的MSVC不AFAIK支持這種表示法。這意味着我不能在需要在Linux和Windows之間移植的代碼中使用它 - 這讓我非常惱火。

+0

不幸的是,我們的工具不符合C99標準。升級工具必須經過管理。 :-( – 2010-05-13 22:12:47

0

幾乎沒有C程序員利用#undef的力量,特別是爲當前目的重新定義一個宏。這使您可以將所有數據設置爲一個可讀的表格,可以在1個位置進行更新和修改。

#define FUNCTION_MAP { \ 
    MAP(ID_NOP_FUNCTION,  NULL), \ 
    MAP(ID_PRINT_FUNCTION, Print), \ 
    MAP(ID_READ_FUNCTION, Read), \ 
    MAP(ID_WRITE_FUNCTION, Write), \ 
    MAP(ID_PROCESS_FUNCTION, Process), \ 
} 

#define MAP(x,y) x 
enum function_enums FUNCTION_MAP; 
#undef MAP 

#define MAP(x,y) y 
Function_Ptr Export_Function_Table[] = FUNCTION_MAP; 
#undef MAP 

別急,還有更全部爲低,價格低$ 0與無標& H,你可以做你的函數頭魔神的全部1位。

#define FUNCTION_MAP \ 
    /* ENUM    Function, return, Arguments ...     */ \ 
    MAP(ID_PRINT_FUNCTION, Print, int, char *fmt, va_list *ap   ) \ 
    MAP(ID_READ_FUNCTION, Read, int, int fd, char *buf, size_t len) \ 
    MAP(ID_WRITE_FUNCTION, Write, int, int fd, char *buf, size_t len) \ 
    MAP(ID_PROCESS_FUNCTION, Process,int, int       ) 

//function enums 
#define MAP(x,y,...) x, 
enum function_enums { FUNCTION_MAP }; 
#undef MAP 

//function pre-definitions with unspecified number of args for function table 
#define MAP(x,fn_name,ret,...) ret fn_name(); 
FUNCTION_MAP 
#undef MAP 

//function tables with unspecified number of arguments 
#define MAP(x,y,...) y, 
typedef int (*Function_Ptr)(); 
Function_Ptr Export_Function_Table[] = { FUNCTION_MAP }; 
#undef MAP 

//function definitions with actual parameter types 
#define MAP(x,fn_name,ret,...) ret fn_name(__VA_ARGS__); 
FUNCTION_MAP 
#undef MAP 

//function strings ... just in case we want to print them 
#define MAP(x,y,...) #y, 
const char *function_strings[] = { FUNCTION_MAP }; 
#undef MAP 

//function enum strings ... just in case we want to print them 
#define MAP(x,y,...) #x, 
const char *function_enum_strings[] = { FUNCTION_MAP }; 
#undef MAP 
#undef FUNCTION_MAP 

現在你可以就在這個頭的頂部添加每個新功能在一個地方,最好是如果你想保留向後兼容的庫FUNCTION_MAP結束......否則你可以只列出他們按字母順序排列。