【问题标题】:Polymorphic function parameters/return values in CC中的多态函数参数/返回值
【发布时间】:2012-07-09 15:08:03
【问题描述】:

我在嵌入式微控制器中工作,我必须将多种类型的数据读/写到非易失性 RAM (NVRAM)。我想避免为每个值编写单独的读/写函数以存储在 NVRAM 中,如下所示:

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 指针和 vtables 的某种组合。我想以更加多态的方式处理这个问题,并拥有以类似方式调用的将每个项目读/写到 NVRAM 的功能。

【问题讨论】:

  • 多态是 C++ 的主要补充之一。这不是 C 的能力。

标签: c polymorphism c89


【解决方案1】:

您可以[非常接近地]使用宏在 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 标头的实现文件中也是如此。

后一种方法具有生成可调试代码的额外好处。 IE。您可以在调试器中单步执行它,就像它通常用于 C++ 模板一样。

【讨论】:

【解决方案2】:

您可以使用 void 指针和大小来做到这一点:

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 中“模拟”模板。

【讨论】:

    【解决方案3】:

    根据目标类型返回不同的类型(几乎?)用 C 是不可能的。不过,您可以用宏来模仿它。例如:

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

    现在您可以编写 write_value() 和 read_value() 以根据长度复制数据,同时考虑内部例程中的字节序。

    【讨论】:

      【解决方案4】:

      C 中没有这样的东西。但是,您可以使用结构方法。

      #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 指针。

      【讨论】:

      • 这很优雅。我希望避免使用巨大的 switch 语句,但工会确实对其进行了一些清理。当我想读/写更复杂的类型(例如结构)或 Endianness 发挥作用时,我觉得在使用联合时有一个问题。
      • 我会使用一个未命名的联合,http://gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html,以避免输入无意义的联合名称
      • 该构造被称为“智能联合”。另一种方法是让所有结构都以 typetag 开头,但会导致需要更多的转换)我会 not 使用未命名的联合,因为它在 ansi C / C89 中是不合法的;是(微软)“扩展”。 (可能被 C99 合法化。这不是很讽刺吗?)
      【解决方案5】:

      查看 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));
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-07-13
        • 1970-01-01
        • 2022-04-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-08-28
        • 2012-08-03
        相关资源
        最近更新 更多