views:

1108

answers:

9

How can I convert the following struct to unsigned char*?

typedef struct {
    unsigned char uc1;
    unsigned char uc2;
    unsigned char uc3;
    unsigned char uc5;
    unsigned char uc6;
} uchar_t;

uchar_t *uc_ptr = new uchar;
unsigned char * uc_ptr2 = static_cast<unsigned char*>(*uc_ptr);
// invalid static cast at the previous line
+1  A: 

Try reinterpret_cast<unsigned char*>. static_cast is for converting between compatible types, like a base class to a derived class. reinterpret_cast is for casts between unrelated types.

John Kugelman
Wow, you beat me to it. 35 seconds ahead of me :)
Jared
+5  A: 

You can't use a static_cast here since there is no relationship between the types. You would have to use reinterpret_cast.

Basically, a static_cast should be used in most cases, whereas reinterpret_cast should probably make you question why you are doing it this way.

Here is a time where you would use static_cast:

class Base {
};

class Derived : Base {
};

Base* foo = new Derived;
Derived* dfoo = static_cast<Derived*>( foo );

Whereas here is where you would probably need a reinterpret_cast:

void SetWindowText( WPARAM wParam, LPARAM lParam )
{
   LPCTSTR strText = reinterpret_cast<LPCTSTR>( lParam );
}
Jared
Thanks John for the edit. I didn't catch that while typing in a hurry.
Jared
In the example you provided the cast to use should be dynamic_cast<> as there is a inheritance relationship. static_cast<> can be used with unrelated (from an inheritance relationship point of view) to convert, for example, an integer to an enumerate type, a double to an int...
David Rodríguez - dribeas
@Jared - you can actually use a static_cast here - see my answer. @dribeas - no a static_cast is fine here - a dynamic_cast actually won't work here since there are no virtual functions in Base - but if there was a virtual destructor - either one of the casts could be used - static_cast would be more efficient of course, although dynamic_cast has certain runtime advantages (not needed in this scenario)
Faisal Vali
+1  A: 

Why would you use such a strange struct instead of:

unsigned char uc[5];

which you can then individually address as uc[0], uc[1], uc[2], uc[3], uc[4] and by pointer to the aggregation (presumably what you want with unsigned char *) by just "uc".

Seems a lot simpler than a struct with multiple unsigned char members that are numbered in the member names (and btw, what happened to uc4? -- another error the array solution would avoid.)

smcameron
I've just noticed the missing uc4. The example I posted is illustrative, the struct I have has some meaning. Thanks anyway.
freitass
+4  A: 

Due to struct packing differences, you can't do this reliably and portably without either using an array to begin with or writing some code that filled a new array one at a time from the struct members by name. A reinterpret_cast might work on one compiler/platform/version and break on another.

You're better off allocating an array on the heap or stack, and then filling it one by one.

Mike Kale
I was about to post the same thing myself. Always write packing/unpacking functions for this sort of thing.
Chris Arguin
You may well be able to get by with some pragmas to control packing, but this is going to be compiler-specific.
Steven Sudit
+1  A: 

How about simply:

unsigned char * uc_ptr2 = &uc_ptr->uc1;
Jim Buck
+1  A: 

The safest, most portable way to convert POD (i.e. C compatible structs) types to unsigned char pointers is not by using reinterpret_cast but by using static_cast (C++0x fixes this and empowers reinterpret_cast to unambiguously have the same portable semantics as the following line of code):

unsigned char *uc_ptr2 = static_cast<unsigned char*>(static_cast<void*>(uc_ptr));

But for all practical purposes, even though the C++03 standard is thought to be somewhat ambiguous on the issue (not so much when converting pointers of class types, but when converting pointers of non-class types to 'unsigned char*'), most implementations will do the right thing if you do use reinterpret_cast as so:

unsigned char *uc_ptr2 = reinterpret_cast<void*>(uc_ptr);

I suspect that you should be fine with alignment issues since your struct contains unsigned chars which can be aligned at any byte, so the compiler won't insert any packing between the members (but strictly speaking, this is implementation dependent, so use caution).

Faisal Vali
A: 

In this case, casting with reinterpret_cast to unsigned char* is guaranteed to work and will point to the first unsigned char data member, because your type is a so-called POD struct (roughly, a C struct).

Quote of the Standard (from 9.2/17, if you wanna look)

A pointer to a POD-struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa. [Note: There might therefore be unnamed padding within a POD-struct object, but not at its beginning, as necessary to achieve appropriate alignment. ]

So the following works

unsigned char * uc_ptr2 = reinterpret_cast<unsigned char*>(uc_ptr);
Johannes Schaub - litb
A: 

Do you want to convert the address of the struct to an address of an unsigned char (as some of the answers assume) or the actual struct to a pointer (as your question indicates)? If the former, here are a few possibilities:

unsigned char * uc_ptr2 = static_cast<unsigned char *>(static_cast<void *>(uc_ptr));
unsigned char * uc_ptr2 = reinterpret_cast<unsigned char *>(uc_ptr);
unsigned char * uc_ptr2 = (unsigned char *)uc_ptr;

If the latter, you can use one of:

unsigned char * uc_ptr2 = *static_cast<unsigned char **>(static_cast<void *>(uc_ptr));
unsigned char * uc_ptr2 = *reinterpret_cast<unsigned char **>(uc_ptr);
unsigned char * uc_ptr2 = *(unsigned char **)uc_ptr;
Ari
A: 

One option is to do the reverse. Create your "unsigned char *" buffer first and then use placement new to allocate your object on top of this buffer.

#include <iostream>

struct  uchar_t {
    unsigned char uc1;
    unsigned char uc2;
    unsigned char uc3;
    unsigned char uc4;
    unsigned char uc5;
    unsigned char uc6;
};

int main ()
{
  unsigned char * buffer
    = new unsigned char[ sizeof (uchar_t)/sizeof (unsigned char) ];
  uchar_t * uc = new (buffer) uchar_t ();

  uc->uc3 = 'a';
  std::cout << buffer[2] << std::endl;

  delete buffer;
}
Richard Corden