在C ++函数中传递原始数据类型的最佳实践

时间:2011-04-10 05:09:32

标签: c++ templates serialization avr

我正在为avr芯片编写一个函数,将字节流反序列化为基本类型。我想以尽可能通用的方式进行,并且想知道确定反序列化类型的最佳实践是什么。我到目前为止的想法包括:

选择A:

// Just write a function for each type
double deserialize_double(uint8_t *in) { }

选择B:

// Use a template, and pass the type in when calling
// Function:
template <typename TYPE>
TYPE deserialize(uint8_t *in) {
  union {
    TYPE real;
    uint8_t base[sizeof(TYPE)];
  } u;

  for (unsigned int i = 0; i < sizeof(TYPE); i++) {
    u.base[i] = in[i];
  }
  return u.real;
}

// Call:
double value = deserialize<double>(in);

选择C:

// Similar to B, but you pass in the type as a parameter
// Function:
TYPE deserialize(uint8_t *in, TYPE);

// Call:
double value = deserialize(in, double);

选择D:

// Use a templated class. My main issue with this is I was hoping 
// to re-use the same object for deserializing multiple types.
template <typename TYPE>
class Serializer {
  public void serialize(uint8_t *out, TYPE value) { /* code */ }
  public TYPE deserialize(uint8_t *int) { /* code */ }
};

有关最佳方法的任何想法吗?也许是一个我忽略的简单方法。

5 个答案:

答案 0 :(得分:3)

首先,C和D是无效选项,因为类型不是有效的函数参数;不妨现在就把它们排除在外。

选择B在这里似乎是明显的胜利者,假设您不关心字节排序或其他使用联合的潜在警告(看起来您不会得到这项工作的背景)。

需要考虑的另一件事是在反序列化时使用一些反馈机制来推进字节流指针/索引。也许你可以试试像

这样的东西
template <typename TYPE>
int deserialize(uint8_t *in, TYPE& value) {
    union {
        TYPE real;
        uint8_t base[sizeof(TYPE)];
    } u;

    for (unsigned int i = 0; i < sizeof(TYPE); i++) {
        u.base[i] = in[i];
    }
    value = u.real;
    return sizeof(TYPE);
}

// Call:
double foo, bar;
int baz;
in += deserialize(in, foo);   // Implicit double deserialize
in += deserialize(in, bar);   // Implicit double deserialize
in += deserialize(in, baz);   // Implicit int deserialize

这有额外的优势(因为我看到@Asha已经打败了我!)允许你利用C ++模板的类型推理系统;由于第二个参数在调用位置具有已知类型,因此无需为TYPE显式指定模板参数。

答案 1 :(得分:2)

还有一个选项是将结果作为“out”参数返回。在这种情况下,您无需在模板实例化期间指定类型。像这样:

template <typename TYPE>
void deserialize(uint8_t *in, TYPE& out) {
  union {
    TYPE real;
    uint8_t base[sizeof(TYPE)];
  } u;

  for (unsigned int i = 0; i < sizeof(TYPE); i++) {
    u.base[i] = in[i];
  }
  out = u.real;
  return;
}

// Call:
double value = 0;
deserialize(in, value);

答案 2 :(得分:1)

提醒:

出于多种原因,通常不建议将C ++用于AVR,并且有些事情根本不会发挥作用 - 所以在花费任何大量时间之前,请小心测试目标芯片上的代码任何特定的道路。

但这并不意味着你必须放弃任何重要的功能。只需调整您的代码以适应可用的语言功能。

答案 3 :(得分:0)

在我看来,选择B 是最好的。它增加了可读性和易用性。 而且,TYPE可以是一些更大的类/结构吗?因为您是通过deserialize()方法按值返回的。

答案 4 :(得分:0)

您应该使用选择A,因为:

  1. 引入最少的复杂性。
  2. 兼容C和C ++。
  3. 如果不支持该类型,则提供直接行为。
  4. 请注意,如果您需要选择B的语法,则始终可以在以后的日期在代码A之上实现该选项(通过为不同类型提供特化)。