【问题标题】:What does reinterpret_cast do binary-wise?reinterpret_cast 以二进制方式做什么?
【发布时间】:2016-06-10 15:00:07
【问题描述】:

我正在用 C++ 编写一个记录器,我已经到了我想要获取日志记录并写入文件的部分。

我创建了一个LogRecord 结构,并希望将其序列化并以二进制模式将其写入文件。

我已经阅读了一些关于 C++ 序列化的帖子,其中一个答案包括以下 sn-p:

reinterpret_cast<char*>(&logRec)

我已尝试阅读有关 reinterpret_cast 及其作用的信息,但我无法完全理解后台实际发生的情况。

据我了解,它需要一个指向我的结构的指针,并将其转换为指向一个字符的指针,所以它认为保存我的结构的内存块实际上是一个字符串,这是真的吗?怎么会这样?

【问题讨论】:

  • "与 static_cast 不同,但与 const_cast 类似,reinterpret_cast 表达式不会编译为任何 CPU 指令。它纯粹是一个编译器指令,指示编译器将表达式的位序列(对象表示)视为如果它的类型为 new_type。”来源:en.cppreference.com/w/cpp/language/reinterpret_cast 接下来发生的事情取决于您的代码 - 在审查代码时将reinterpret_cast 视为一个重要的警告标志。
  • 不是“实际上是一个字符串”而是“实际上是一个指向char的指针”。字符串只是char* 的用途之一。
  • reinterpret_cast的可能重复
  • 出于可维护性的目的,最好隐藏这些低级实现细节。您还必须非常小心对齐以及将来您可能希望向该结构添加字段的可能性。在某些情况下,基于文本的序列化可能更可取...
  • 用二进制写入整个结构记录不一定可移植,即使在同一编译器的不同版本之间,甚至在使用不同编译标志的相同编译器版本的不同编译之间也不一定可移植。对于有一定持续时间的日志文件,我建议单独编写每个字段。此外,如果您想要平台兼容性,您可能希望以网络字节顺序输出数字字段。

标签: c++ struct casting


【解决方案1】:

内存地址只是一个内存地址。内存本身并不特殊 - 它只是一个巨大的字节数组,我们关心的只是。赋予记忆意义的是我们如何处理它,以及我们观察它的镜头。

指向结构的指针只是一个整数,它指定了内存中的某个偏移量——当然,在你的情况下,你可以以任何你想要的方式将一个整数视为指向任意字节数的指针 (chars) .

reinterpret_cast() 没有做任何特别的事情,只是允许您将内存地址的一个视图转换为内存地址的另一个视图。正确处理该内存地址仍取决于您。

例如,char* 是在 C++ 中引用字符串的传统方式 - 但类型 char* 字面意思是“指向单个字符的指针”。它是如何表示指向以空字符结尾的字符串的指针的?按照惯例,就是这样。我们会根据上下文对类型进行不同的处理,但要确保我们这样做正确。

例如,您如何知道通过指向结构的char* 指针读取多少字节?类型本身为您提供零信息 - 由您决定是否确实有一个面向字节的指针,指向一个固定长度的结构。

请记住,在引擎盖下,机器没有类型。一张纸不在乎你是否在每一行上写一篇文章,或者你是否在整个东西上乱涂乱画。这就是我们对待它的方式——以及我们使用的工具 (C++) 对待它的方式。

【讨论】:

  • 哇,@antiduh,谢谢!你的回答真的帮助我理解了我通过编码在做什么。这似乎很合乎逻辑,可能对大多数人来说都是既定的,但直到现在我才这么想!
【解决方案2】:

在二进制方面,它什么都不做。这种铸造是一个更高层次的概念,与任何实际的机器指令无关。

在底层,指针只是一个保存内存地址的数值。告诉编译器“虽然你认为目标内存包含struct,但现在请认为它包含char”没有什么可做的。实际地址本身不会发生任何变化。

【讨论】:

    【解决方案3】:

    据我了解,它需要一个指向我的结构的指针,并将其转换为一个指向字符的指针,所以它认为保存我的结构的内存块实际上是一个字符串,是真的吗?

    是的。

    这怎么行?

    字符串只是一个字节序列,而你的对象只是一个字节序列,所以它是这样工作的。

    但如果您的对象逻辑上不仅仅是一个字节序列,它不会。任何间接,你都会被淹没。此外,任何实现定义的填充或表示/字节序以及您的数据都是不可移植的。这可能是可以接受的;这真的取决于你的要求。

    【讨论】:

      【解决方案4】:

      将结构转换为字节(字符)数组是二进制序列化的经典低影响方法。这是基于结构的内容在内存中连续存在的假设。转换允许我们使用普通 API 将这些数据写入文件或套接字。

      这只有在数据是连续的情况下才有效。对于 C++ 术语中的 C 样式结构或 POD,这是正确的。它不适用于复杂的 C++ 对象或任何带有指向结构外部存储的指针的结构。对于文本数据,您需要使用固定大小的字符数组。

      struct {
          int num;
          char name[50];
      };
      

      将正确序列化。

      struct {
          int num;
          char* name;
      };
      

      由于字符串的数据存储在结构之外,因此无法正确序列化;

      如果您通过网络发送数据,您还需要确保结构已打包或至少具有已知对齐方式,并且整数转换为一致的字节序(网络字节顺序通常为大字节序)

      【讨论】:

        猜你喜欢
        • 2016-03-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-01
        相关资源
        最近更新 更多