【问题标题】:How to distinguish PODs and non PODs? [closed]如何区分 POD 和非 POD? [关闭]
【发布时间】:2019-09-01 17:43:17
【问题描述】:

我有一个文件处理程序,用于读取和写入自定义二进制文件。为了节省自己的工作,我从一个基本结构 (base_p) 继承了多个数据:

struct base_p{
  protected:
      uint32_t v0= 0;
      uint32_t v1= 0;
      uint32_t v2= 0;
  friend struct f_block;
  // other friends
};

现在在构建该文件的内部块期间,我将该结构继承到多个非 POD 类型中:

struct f_block:public base_p{
   f_block(){
      this->v0 = 0x3f580058; // an magic number of the block
      this->v1 = 0x1000004D; // version and use type
      this->v2 = 0;
   }
   f_block(uint32_t data){
      this->v0 = 0x3f580058; // an magic number of the block
      this->v1 = 0x1000004D; // version and usage type
      this->v2 = data;
   }

  operator uint8_t(){ return this->v1 & 0xff; }
  operator bool(){return this->v2 != 0 ;}
  friend std::ostream& operator<<( std::ostream& os, f_block& fb );
};
std::ostream& operator<<( std::ostream& os, f_block& fb ){
    union {
        uint32_t vrt;
        unsigned char parts[4];
    }temp;
    temp. vrt = fb. v2;
    return os << temp. parts[3] << temp. parts[2] << temp. parts[1] << temp. parts[0];
}

在我的文件处理程序中,我使用了这两种结构。例如,如果我需要在某处传递数据,我需要将数据提取为base_p。但是我的块定义有一个额外的功能,usage 服务和压缩密钥,在data (v2) 中,我还存储了一些信息,例如从末尾的位偏移量、特征块的长度。 . .和许多其他人。所以提取函数看起来有点像:

struct file_handler{
   std::vector<base_p> data;
   file_handler():data(0){}
   virtual bool read(const char *filename) = 0; // to be overridden
   virtual bool write(const char *filename)= 0; // to be overridden  

   virtual bool set( base_p &data){
      // if data is base_p , push_back data as normal POD  
      // if data is f_block, push_back data as deflated version  
      // don't store anything in vector if none
   }
   virtual bool get( base_p &data){
      // if data is base_p, returns lasts 3 elements v2(data) fields
      // if data is f_block, returns last element as f_block - inflated, 
      // set data as 0 if none
   }
}

我试图捕捉调用base_p 中不存在的函数的错误,但它不适合我,因为我在应该接受其他数据类型的file_handler 结构上构建多个文件处理程序.一旦我能够成功实现file_handler,我就足够安全地开始构建其他文件类型。我需要的是数据类型 switch 语句。

由于我来自python 背景,我可以在其中做一些类似于isinstance 或类似的事情。但这是 C++,所以没有这样的实现 - 我知道


我已经搜索并发现了一些似乎有可能解决我的问题的元素,但它们中的大多数都是过时的版本,或者太抽象而无法将我的头脑包裹起来以生成逻辑解决方案。

  • SFINAE and void :提到 SFINAE 遵循的某种 concept,以及 compound 概念,这对我来说太抽象了,无法成功地进行有效实施。
  • HasMember SFINAE :这对于构造函数识别似乎是可行的,但最好的答案写在 c++03 中,没有提及它是否转换为 c++11 也就是我目前使用的版本。

有没有办法区分 POD 和非 POD?

【问题讨论】:

标签: c++ c++11


【解决方案1】:

我来自python背景

C++ 不是 Python。

如果你只有一个void* 并且不知道它来自哪里或它指向什么对象,那么你无能为力。 C++ 是一种静态类型语言。这意味着对象不会自动在其自身存储任何东西,从而将它们标识为特定类型。所有这些类型信息都是在编译时根据编译器在代码中看到的类型完成的。

这里出现的类型是void,它是“非类型”类型。因此,任何打字信息都已丢失。并且无法通过查看void* 后面的一些字节来恢复它。

void* 后面的第一个字节的内容而言,指向subs 的指针和指向my_data 的指针之间没有区别

【讨论】:

  • 我编辑了这个问题。请检查它是否使事情更清楚。
【解决方案2】:

听起来您希望能够获取任意字节块,并确定这些字节是否构成 my_data 类型实例的底层表示。

你不能。没有这样的事情是有意义的。这些字节没有类型

您将不得不手动反序列化字节,使用您设计的规则,挑选其中的值(当这样解释时)是否与my_data 对象中的值的先决条件相匹配。

通常我们会用一些“标题”自己管理数据,表示“这是my_type 的一个实例”,这样您至少有一些的可能性知道它是这样的(不要忘记这个标头可能仍然会在任意数据中找到,这纯属偶然)。但是您还需要将该逻辑构建到 序列化 阶段(即将退出)。

【讨论】:

  • 类似的东西。我将尝试用最简单的方式解释我对它的需求。我有我的数据,我有管理序列化和反序列化的句柄。但是这些数据可以附加到 PE 或其他文件中。附加字节遵循与我的任何数据自定义块相似的结构(带有该使用标志)和 3 个字节的魔法和 4 个字节的校验和 - 继续前进”。然后使用反序列化对它的一部分下标并改变它的一部分。
  • 但是如果我读取 PE 或其他文件的不同部分,并且我的句柄试图反序列化它(做一些错误或错误),我需要我的句柄说“这不是你的数据,这是 POD 或类似的东西……你什么也得不到”。句柄应该检查它应该如何通过管理它的“使用”静态成员来反序列化数据。因此,如果我有一个附加文件说它从后面开始 50 个字节,但它实际上从 51 开始,并且发生了一些损坏并且魔法是真实的。我将被反序列化的不是我的数据。
  • 无论“您的序列化和反序列化处理”做什么,由他们来做任何需要的事情,以便您的代码可以识别这是“您的数据”。 C++ 中没有任何东西可以为您做到这一点。 C++ 不能以这种方式工作。你所拥有的只是一个二进制数据块。您必须决定这个二进制 blob 的外观,以便它代表您的“数据”,然后反序列化。当然,如果你猜错了,你的反序列化代码将会失败,你将不得不以任何你认为合适的方式处理反序列化错误。另一个答案总结了一切。
  • @Danilo 您一直试图区分“您的数据”和“POD”,但我无法弄清楚这种区别是什么。
  • 你一遍又一遍地描述了你想做的事情。您似乎不明白的是,C++ 语言本身没有什么可以为您完成所有这些工作,您必须自己实现所有这些工作。最基本的方法是将一些特定的值写入文件,在任何 POD 的内容之前,或写入任何内容。当您回读它时,您会读取该值并知道紧随其后的是哪个特定的 POD 或其他任何东西,然后您对其进行反序列化。就是这样。基本上,这就是 Python 在内部执行此操作的方式。 C++ 不是 Python,你必须自己做。
猜你喜欢
  • 2011-01-18
  • 2021-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-13
  • 2023-03-04
  • 2020-06-05
相关资源
最近更新 更多