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

Best practice for passing primitive data type in C++ function

本文关键字:数据类型 最佳 原始 c++ 函数      更新时间:2023-10-16

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

选择

:

// 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 */ }
};

有什么最好的办法吗?也许我忽略了一个更简单的方法。

首先,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指定模板实参。

另一个选项是将结果作为"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);

警告:

通常不推荐使用c++进行AVR,原因有很多,而且有些事情完全无法工作——所以在投入大量时间进行任何特定的路径之前,请仔细在目标芯片上测试您的代码。

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

在我看来选择B是最好的。它增加了更多的可读性和易于使用。此外,TYPE也可以是更大的类/结构吗?因为您是按deserialize()方法的值返回的!

你应该选择A,因为:

  1. 它引入了最少的复杂性。
  2. 兼容C和c++。
  3. 如果不支持该类型,则提供直接的行为。

请注意,如果您想要选择B的语法,总是可以在以后的日期在选择A的代码之上实现它(通过为不同类型提供专门化)。