views:

1209

answers:

5

I have a (void*) buffer that I need to convert to std::vector<unsigned char> before I can pass it on. Unfortunately, my C++ casting skills a little weak. Any suggestions?

+10  A: 

You will need the length of the buffer. Once you do, we can do this:

unsigned char *charBuf = (unsigned char*)voidBuf;
/* create a vector by copying out the contents of charBuf */
std::vector<unsigned char> v(charBuf, charBuf + len);

Okay, the comment got me started on why I did not use reinterpret_cast:

  • In C++, the C-style cast is a convenience function -- it asks the compiler to choose the safest and most portable form of conversion over the set of available cast operators.

  • The reinterpret_cast is implementation defined and should always be the last thing on your mind (and used when you are necessarily doing a non-portable thing knowingly).

  • The conversion between (unsigned doesn't change the type) char * and void * is portable (you could actually use static_cast if you are really picky).

The problem with the C-style cast is: the added flexibility can cause heartaches when the pointer type changes.

Note: I agree with the general convention of not casting as much as possible. However, without any source provided, this is the best I could do.

dirkgently
reinterpret_cast is easier to grep for.
Thomas L Holaday
and both should be avoided
anon
@tlholaday: static_cast<> can be used to cast to void*, so it should be used instead.
j_random_hacker
@dirkgently: +1, but please indicate that this creates a *copy* of the buffer -- that's important, but not obvious from your post.
j_random_hacker
@j_random_hacker: OP mentioned 'passing' -- I assumed he meant a copy. Anyway, updated source with comments.
dirkgently
yeah if anything, why not static_cast<>. it's not impl defined, it's portable. it's just not convenient. but it's much safer :) anyway, you've provided rationale why you did use c-style cast. like it, so +1 :D
Johannes Schaub - litb
that said, i actually think casting from void* to any object pointer is undefined behavior when done with reinterpret_cast. the standard says one can cast between two pointers that have pointer-to-object type. but void* is pointer-to-void-type. though i imagine that's an uncommon interpretation
Johannes Schaub - litb
@litb: IIRC, lookup the section on safely derived pointer values. That section may have an answer.
dirkgently
i will have a look into the revisions of c++03. i can't find anything in c++98 that allows it. but ill tell you if i find it. cheers :)
Johannes Schaub - litb
@litb: I meant look up C++0x drafts. Will keep watching.
dirkgently
+2  A: 

You can't simply cast a void* to a std::vector<unsigned char> because the memory layout of the latter includes other objects, such as the size and the number of bytes currently allocated.

Assuming the buffer is pointed to by buf and its length is n:

vector<unsigned char> vuc(static_cast<char*>(buf), static_cast<char*>(buf) + n);

will create a copy of the buffer that you can safely use.

[EDIT: Added static_cast<char*>, which is needed for pointer arithmetic.]

j_random_hacker
+5  A: 

You should not be doing any casting - full-stop. Please post some code that illustrates your question - I really don't understand what you mean by a "(void*) buffer".

anon
A void* buffer is just a pointer to a memory region of unknown type -- C programs are full of them.
j_random_hacker
j_random_hacker
@j_random then it is a pretty useless buffer, given that you cannot dereference a void * and thus cannot access the buffer contents
anon
Real-life void* buffer example: generally, any C-style (e.g. OS API) function that works with callback functions will call that function with (at least) one opaque void* parameter, which the callback function will need to interpret in whatever fashion is appropriate (obviously requiring a cast).
j_random_hacker
E.g. qsort() calls its comparator function with two const void* arguments for the elements to compare -- obviously, the user-supplied comparator function must cast those pointers to the (known) type of the elements before using them.
j_random_hacker
Have you never worked with C? There is no better (typesafe) way to do this sort of thing in C-land.
j_random_hacker
but this question was about C++.
anon
@Neil: yes, it was about C++, but a helluva lot of extant C++ code is just thinly disguised C. Anyone maintaining an app over 5 years old, and anyone dealing directly with OS or other C-based APIs, needs to know what void* is and how it's used in practice.
j_random_hacker
+2  A: 

using std::vector class for an already allocated buffer is not a solution. A std::vector object manages the memory and deallocates it at destruction time.

A complicated solution might be to write your own allocator, that uses an already allocated buffer, but you have to be very careful on several scenarios, like vector resizing, etc.

If you have that void* buffer bound through some C API functions, then you can forget about conversion to std::vector.

If you need only a copy of that buffer, it can be done like this:

std::vector< unsigned char> cpy( 
    (unsigned char*)buffer, (unsigned char*)buffer + bufferSize);

where bufferSize is the size in chars of the copied buffer.

Cătălin Pitiș
A: 
teeks99