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

发布于 2024-10-31 16:06:14 字数 1180 浏览 1 评论 0原文

我正在为 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 */ }
};

关于最好的方法有什么想法吗?也许是我忽略的一个更简单的方法。

I'm writing a function for an avr chip to deserialize a byte stream to primitive types. I'd like to do it in as generic a way as possible and was wondering what the best practice would be to determine the type to deserialize. Ideas I have so far, include:

Choice A:

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

Choice 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);

Choice 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);

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

Any ideas on the best way to do this? Perhaps an easier method I overlooked.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

万人眼中万个我 2024-11-07 16:06:14

对于初学者来说,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 模板参数。

For starters, C and D are invalid options because types are not valid function arguments; might as well rule them out right now.

Choice B seems like the clear winner here, assuming you aren't concerned about byte ordering or other potential caveats of using a union as you are (it doesn't seem like you would be given the context of this work).

One additional thing to consider is having some feedback mechanism to advance your bytestream pointer/index as you deserialize. Perhaps you could try something like

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

This has the additional advantage (as I see @Asha beat me to it already!) of allowing you to take advantage of C++ templates' type inference system; since the second argument has a known type at the call location, there is no need to explicitly specify a template argument for TYPE.

眼泪都笑了 2024-11-07 16:06:14

另一种选择是将结果作为“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);

One more option is to return the result as an "out" parameter. In that case you need not specify the type during the instantiation of the template. Something like this:

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);
ι不睡觉的鱼゛ 2024-11-07 16:06:14

需要注意的是:

出于多种原因,通常不建议在 AVR 中使用 C++,而且有些东西根本无法工作——因此,在投入大量时间之前,请务必小心地在目标芯片上测试代码。走任何特定的道路。

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

A word of caution:

Using C++ for an AVR is not usually recommended for a number of reasons, and a some things flat out won't work at all -- so be careful to test your code on your target chip before putting any significant time into going down any specific path.

But that doesn't mean you have to give up any significant functionality. Just adapt your code to suit the available language features.

夏花。依旧 2024-11-07 16:06:14

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

In my view Choice B is the best. It adds more readability and easy to use.
Moreover, is TYPE can be some bigger class/struct also ? Because you are returning by value from your deserialize() method !

空城旧梦 2024-11-07 16:06:14

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

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

请注意,如果您需要选项 B 的语法,则始终可以稍后在选项 A 的代码之上实现该语法(通过为不同类型提供专门化)。

You should use Choice A because:

  1. It introduces the least complexity.
  2. Is compatible with both C and C++.
  3. Provides straight-forward behavior if the type is not supported.

Note that if you desire the syntax of Choice B, it is always possible to implement that on top of the code for Choice A at a later date (by providing specializations for the different types).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文