【问题标题】:Casting void pointers, depending on data (C++)根据数据转换 void 指针 (C++)
【发布时间】:2009-05-27 00:57:36
【问题描述】:

基本上我想要做的是,根据某些变量,将 void 指针转换为不同的数据类型。例如('cast' 变量只是为了表达我的观点):

void* ptr = some data;
int temp = some data;
int i = 0;

...

if(temp == 32)      cast = (uint32*)
else if(temp == 16) cast = (uint16*)
else                cast = (uint8*)

i = someArray[*((cast)ptr)];

C++ 中是否有任何东西可以做这样的事情(因为您实际上不能将变量分配为只是 (uint32*) 或类似的东西)?如果不清楚,我深表歉意,任何帮助将不胜感激。

【问题讨论】:

  • 为什么不一边做演员一边做测试? if (temp==32) index = (uint32*)ptr; //等等
  • 是的,这是显而易见的方式,但如果我这样做,我将需要数百个 if...else。 if(temp==32)i = someArray[*index32];否则 if(temp==16)i = someArray[*index16];等等。我希望有一些简单的方法可以做到这一点,如上所述。
  • 您还需要数百个 if/else?
  • 我很抱歉,在我要做的程序中,它需要数百个。这就是我试图找到解决方案的原因。

标签: c++ casting void-pointers


【解决方案1】:

“正确”的方式:

union MyUnion
{
     uint32 asUint32;
     uint16 asUint16;
     uint8 asUint8;
}

uint32 to_index(int size, MyUnion* ptr) 
{  
    if (size== 32) return ptr->asUint32;  
    if (size== 16) return ptr->asUint16;
    if (size== 8) return ptr->asUint8;  
}

i = someArray[to_index(temp,ptr)]

[更新:修正了愚蠢的错字]

【讨论】:

  • 三个条件句中的意思是“size”而不是“temp”?
【解决方案2】:

显然,boost::variant 是要走的路。它已经存储了一个类型标签,使您无法转换为错误的类型,并在编译器的帮助下确保了这一点。这是它的工作原理

typedef boost::variant<uint32_t*, uint16_t*, uint8_t*> v_type;

// this will get a 32bit value, regardless of what is contained. Never overflows
struct PromotingVisitor : boost::static_visitor<uint32_t> {
    template<typename T> uint32_t operator()(T* t) const { return *t; }
};

v_type v(some_ptr); // may be either of the three pointers

// automatically figures out what pointer is stored, calls operator() with
// the correct type, and returns the result as an uint32_t.
int i = someArray[boost::apply_visitor(PromotingVisitor(), v)];

【讨论】:

    【解决方案3】:

    更清洁的解决方案:

    uint32 to_index(int temp, void* ptr) {
      if (temp == 32) return *((uint32*)ptr);
      if (temp == 16) return *((uint16*)ptr);
      if (temp == 8) return *((uint8*)ptr);
      assert(0);
    }
    
    i = someArray[to_index(temp,ptr)]
    

    【讨论】:

      【解决方案4】:

      听起来你可能是在联合之后,或者如果你正在使用 Visual Studio 一个_variant_t。或者也许 typeinfo() 会有所帮助? (说实话,我不太确定你到底想做什么)。

      就转换而言,您几乎可以将任何东西转换为任何东西——这就是 C++ 危险的原因(如果您真的很小心,它也很强大)。

      另外,请注意,指针值在大多数平台上都是 32 位或 64 位的,因此您无法在 32 位平台上将 uint64 存储在 void* 中。

      最后,也许这就是你想要的:

      void* p = whatever;
      
      uint32 x = (uint32)p;
      

      或许

      uint32 source = 6;
      
      void* p = &source;
      
      uint32 dest = *((uint32*)p);
      
      void* p =
      

      【讨论】:

        【解决方案5】:

        如果您被锁定使用 void ptr,并且绝对需要使用不同类型调用 []:

        template <typename cast_to>
        inline
        int get_int_helper(someArray_t someArray, void* ptr) {
           return someArray[*static_cast<cast_to*>(ptr)];
        }
        
        int get_int(someArray_t someArray, void* ptr, int temp) {
           switch ( temp ) {
              case 32: return get_int_helper<uint32>(someArray,ptr);
              case 16: return get_int_helper<uint16>(someArray,ptr);
              default: return get_int_helper<uint8>(someArray,ptr);
           }
        }
        

        但是,正如其他人指出的那样;可能有更好/其他的方法来做到这一点。最有可能的是,您拥有的任何数组都没有多个运算符 [],因此它不需要不同的类型。此外,您可以使用 boost::variant 来保存类型的可区分联合,这样您就不必传递 temp

        【讨论】:

          【解决方案6】:

          您似乎想要存储接受 void* 并生成无符号整数的“cast”函数。所以,让它成为一个函数:

          std::map<int, boost::function<unsigned(*)(void*)> casts;
          template <typename T> unsigned cast(void* v) { return *(T*)v; }
          casts[32] = cast<uint32>;
          casts[16] = cast<uint16>;
          casts[8] = cast<uint8>;
          casts[128] = MySpecialCastFromDouble;
          
          void* foo = getFoo();
          unsigned bar = casts[16](foo);
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-07-31
            • 2021-02-28
            • 2012-11-21
            • 2013-03-10
            • 2021-09-20
            • 1970-01-01
            相关资源
            最近更新 更多