2012-07-09 114 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