【问题标题】:Casting void* to several types known only at runtime将 void* 转换为仅在运行时已知的几种类型
【发布时间】:2015-02-24 08:51:18
【问题描述】:

我正在将我的 C++ 程序连接到 C++ 框架。

框架返回一个 void* 指针,它指向使用 malloc() 初始化的一组数据:

void* getData() {
    return framework->returnPointer();
}

只有在运行时才知道数据的类型(来自我的程序),框架具有以下功能:

size_t ndf_sizeof(ndf_typeid id) {
    switch(id) {
        case NDF_INT64:
            return sizeof(int64_t);
        case NDF_FLOAT:
            return sizeof(float);
        case NDF_DOUBLE:
            return sizeof(double);
    }
    return 0;
}

数据可以采用几种不同的类型,类型存储为 ndf_type(即数据类型的整数标识符)。数据在运行时不会改变类型。我可以取回数据的ndf_type,也可以取回数据的大小。

我需要能够做两件事:

  1. 在运行时声明并初始化一个与数据相同类型的缓冲区
  2. 遍历数据并将值放入我的缓冲区

当处理 void* 指针并且仅在运行时知道数据类型时,我遇到了困难,它本身可以采用几种不同的类型。我曾尝试使用模板和通用数据结构,但无济于事。

非常感谢此问题的解决方案。

【问题讨论】:

    标签: c++ malloc void-pointers generic-programming


    【解决方案1】:

    由于声明发生在编译时,您不能在运行时声明类型。

    但是,您可以在编译时声明所有可能的类型,准备这些类型的指针,并在运行时强制转换为适当的指针。应您的要求,我详细说明。

    我假设你有一个指针,比如:void * raw_data,并且你知道类型,ndf_typeid id。

    你可以这样分配你需要的指针:

    int64_t *p1 = 0;
    float   *p2 = 0;
    double  *p3 = 0;
    switch(id) {
        case NDF_INT64:   p0 = (int64_t  *) raw_data; break;
        case NDF_FLOAT:   p1 = (float    *) raw_data; break;
        case NDF_DOUBLE:  p2 = (double   *) raw_data; break;
    }
    

    然而,真正的工作在那之后才开始——你想做某事,并且你将有很多“if”和“case”语句来执行你想要执行的代码。这就是为什么有时人们会使用虚方法:

    struct Any {
       size_t _size;
       virtual void doit() = 0;
    };
    
    template < typename T > struct Typ: Any {
       T _data;
       Typ ( void * data ): _size(sizeof(T)), _data(*(T*)data) {}
       virtual void doit {
          cout << _data << " has size " << _size;
       }
    }
    
    Any * any = 0;
    
    switch(id) {
       case NDF_INT64:   any = new Typ<int64_t> (raw_data); break;
       case NDF_FLOAT:   any = new Typ<float  > (raw_data); break;
       case NDF_DOUBLE:  any = new Typ<double > (raw_data); break;
    }
    
    any->doit();
    

    这只会打印出值。您可以为每个 Typ 覆盖 doit 然后:

    template<> void Typ<float>::doit() {
       cout << "this is a float: " << _data;
    }
    

    这使您可以根据类型进行不同的工作。

    【讨论】:

    • 您能进一步解释一下吗?
    【解决方案2】:

    在运行时声明并初始化一个与数据相同类型的缓冲区

    不,您不能这样做,因为您不知道数据实际上是什么类型。最接近的方法是声明支持每种类型的缓冲区,然后在运行时决定需要填充哪个缓冲区。

    【讨论】:

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