2012-07-09 234 views
1

我正在嵌入式微控制器中工作,我必須將多種數據讀/寫到非易失性RAM(NVRAM)中。我想,以避免不必編寫單獨的讀/寫功能爲每個值在NVRAM中存儲這樣的:多態函數參數/返回值C

void Write_Value1(int value); 
int Read_Value1(void); 
void Write_Value2(unsigned long value); 
unsigned long Read_Value2(void); 
... 

那肯定是麻煩的維護作爲項目列表讀/寫的增長。有幾種方法可以用C++來解決這個問題,例如模板。使用模板我可以編寫一個.Read().Write(T value)函數,每個項目要讀取/寫入將有權訪問。無論如何,從C獲得這種行爲?我懷疑有一些方法,使用void指針和vtable的組合。我想以更多樣化的方式處理這個問題,並且具有將每個項目讀取/寫入到以類似方式調用的NVRAM的功能。

+0

多態性是C++的主要附加元素之一。這不是C的能力。 – trumpetlicks 2012-07-09 15:11:34

回答

4

你可以用空指針和大小做到這一點:

void write_value (void *data, size_t size); 
void* read_value (size_t size); 

然後:

write_value ((void *) &int_val, sizeof (int)); 
write_value ((void *) &ulong_val, sizeof (unsigned long)); 

intptr = read_value (sizeof (int)); 
charptr = read_value (sizeof (char)); 

read_value則需要malloc的東西,並將其返回。有時候,這可能只是開銷,當你想讀一個自動的。然後做:

/* Declaration. */ 
void read_value (void *data, size_t size); 

/* Use. */ 
read_value (&automatic_var, sizeof (automatic_var)); 

最後,你可以在all sorts of ways'模擬'模板。

+0

閱讀的外觀與不同的尺寸會如何返回? – 2012-07-09 15:19:01

+0

@JoelB - 我做了一個編輯來表明這一點。 – ArjunShankar 2012-07-09 15:23:34

3

根據目標類型返回不同的類型(幾乎?)不可能使用C語言。但是,您可以使用宏來模擬它。例如:

#define WRITE(x) write_value(x, sizeof(x)) 
#define READ(x) read_value(&x, sizeof(x)) 

現在你可以出基於長度寫write_value()和read_value()來複制數據,考慮到字節序在您的內部程序。

2

看POSIX的readwrite功能,只是做同樣的事情:

void read(int address, void * data, int size); 
void write(int address, const void * data, int size); 

再後來:

read(address, &x, sizeof(x)); 
write(address, &x, sizeof(x)); 
3

中有C.沒有這樣的事情。然而,你可以使用一個struct做法。

#define T_VOID 0 
#define T_INT 1 
#define T_ULINT 2 

typedef struct 
{ 
    int type; 
    union 
    {    
     int a; 
     unsigned long b; 
    } my_union; 
} my_struct; 

void write_value(my_struct *s) 
{ 
    switch (s->type) 
    { 
     case T_VOID: 
     // do something 
     break; 
     case T_INT: 
     // do something with s->my_union.a 
     break; 
     case T_ULINT: 
     // do something with s->my_union.b 
     break; 
    } 
} 

以相同的方式,read_value會返回一個my_struct指針。

+0

+1111!這是一種更安全的方法。 – Linuxios 2012-07-09 15:18:53

+1

這非常優雅。我希望避免一個巨大的切換聲明,但工會確實清理了一下。我覺得當我想要讀/寫更復雜的類型(例如圖表)或Endianness發揮作用時,在使用聯合的地方有一個問題。 – 2012-07-09 15:31:27

+1

我會使用一個未命名的聯盟,[http://gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html](http://gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html) ,所以爲了避免輸入毫無意義的聯合名字 – amc 2012-07-09 15:36:17

10

您可以[非常接近]使用宏模擬C語言中的C++模板。

至少有兩種方法可以做到這一點。


第一種方法: 「橡皮圖章」 宏

定義聲明/定義宏爲你的函數

#define DECLARE_READ_WRITE(suffix, type)\ 
    type Read_Value_##suffix(void); 
    void Write_Value_##suffix(type val); 

#define DEFINE_READ_WRITE(suffix, type)\ 
    type Read_Value_##suffix(void) {\ 
    /* your code */ \ 
    }\ 
  void Write_Value_##suffix(type val) {\ 
    /* your code */ \ 
    } 

,然後在一些頭文件中做

DECLARE_READ_WRITE(long, long) 
DECLARE_READ_WRITE(int, int) 

並在一些實施文件

DEFINE_READ_WRITE(long, long) 
DEFINE_READ_WRITE(int, int) 

將 「生成」 爲Read_Value_intWrite_Value_intRead_value_longWrite_value_long聲明和定義。


方法二:參數包括文件

創建兩個頭文件。一個用於聲明(read_write.h.template

TYPE__ CONCAT(Read_Value_, SUFFIX__)(void); 
void CONCAT(Write_Value_, SUFFIX__)(TYPE__ val); 

,一個用於定義(read_write.c.template

TYPE__ CONCAT(Read_Value_, SUFFIX__)(void) 
{ 
    /* your code */ 
} 

void CONCAT(Write_Value_, SUFFIX__)(TYPE__ val) 
{ 
    /* your code */ 
} 

這裏CONCAT是一個通常的實現宏令牌級聯的(可以/應當在第一方法中使用爲好) 。

然後包括你的「模板」的代碼到一個適當的頭文件和執行文件

#define TYPE__ int 
#define SUFFIX__ int 
#include "read_write.h.template" 
#undef TYPE__ 
#undef SUFFIX__ 

#define TYPE__ long 
#define SUFFIX__ long 
#include "read_write.h.template" 
#undef TYPE__ 
#undef SUFFIX__ 

read_write.c.template頭部分實現文件同樣的事情。

後一種方法具有生成可調試代碼的附加好處。即您可以在調試器中單步執行它,就像它通常用於C++模板一樣。

+0

如果你有興趣,有一個完整的問題,專門用於模擬C中的模板:http://stackoverflow.com/q/10950828/274261 – ArjunShankar 2012-07-09 15:30:25

+0

也http: //stackoverflow.com/questions/7186103/how-to-elegantly-implement-a-series-of-functions-in-different-type-versions-usin – AnT 2012-07-09 18:39:06