Casting void pointers, depending on data (C++)

2019-06-11 02:38发布

Basically what I want to do is, depending on the some variable, to cast a void pointer into a different datatype. For example (the 'cast' variable is just something in order to get my point across):

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

Is there anything in C++ that can do something like this (since you can't actually assign a variable to be just (uint32*) or something similar)? I apologize if this isn't clear, any help would be greatly appreciated.

6条回答
劫难
2楼-- · 2019-06-11 03:17

It seems you want to store the "cast" function that takes a void* and produces an unsigned integer. So, make it a function:

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);
查看更多
ゆ 、 Hurt°
3楼-- · 2019-06-11 03:23

The "correct" way:

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)]

[update: fixed dumb typo]

查看更多
贪生不怕死
4楼-- · 2019-06-11 03:24

If you were locked into using a void ptr, and absolutely needed to call [] with different types:

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

However, as others have pointed out; there are probably better/other ways to do it. Most likely, whatever array you have doesn't have multiple operator[], so it doesn't need the different types. In addition, you could be using boost::variant to hold a discriminated union of the types so you wouldn't have to pass around temp

查看更多
Juvenile、少年°
5楼-- · 2019-06-11 03:28

Clearly, boost::variant is the way to go. It already stores a type-tag that makes it impossible for you to cast to the wrong type, ensuring this using the help of the compiler. Here is how it works

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)];
查看更多
三岁会撩人
6楼-- · 2019-06-11 03:35

A cleaner solution:

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)]
查看更多
Explosion°爆炸
7楼-- · 2019-06-11 03:37

It sounds like maybe you're after a union, or if you're using Visual Studio a _variant_t. Or maybe typeinfo() would be helpful? (To be honest, I'm not quite sure exactly what you're trying to do).

As far as the casts, you can cast just about anything to anything -- that's what makes C++ dangerous (and powerful if you're really careful).

Also, note that pointer values are 32-bit or 64-bit in most platforms, so you couldn't store a uint64 in a void* on a 32-bit platform.

Finally, maybe this is what you want:

void* p = whatever;

uint32 x = (uint32)p;

or maybe

uint32 source = 6;

void* p = &source;

uint32 dest = *((uint32*)p);

void* p =
查看更多
登录 后发表回答