7
error: invalid static_cast from type ‘unsigned char*’ to type ‘uint32_t* {aka unsigned int*}’
     uint32_t *starti = static_cast<uint32_t*>(&memory[164]);

I've allocated an array of chars, and I want to read 4 bytes as a 32bit int, but I get a compiler error. I know that I can bit shift, like this:

(start[0] << 24) + (start[1] << 16) + (start[2] << 8) + start[3];

And it will do the same thing, but this is a lot of extra work.

Is it possible to just cast those four bytes as an int somehow?

David Mulder
  • 7,595
  • 11
  • 45
  • 61
  • Yup. `uint32_t val = *(uint32_t*)((void*)(memory+164));` – IdeaHat Mar 31 '14 at 19:21
  • Have a look here: http://stackoverflow.com/questions/2473628/c-cant-static-cast-from-double-to-int?rq=1 – Marius Mar 31 '14 at 19:21
  • It should be noted that doing this is not very `c++`-y. For example, if 'memory' comes from a file or from the network, you'll need to worry about endianess. – mic_e Mar 31 '14 at 19:23
  • 1
    @mic_e I'm working on a binary translator from pa-risc to x86_64. I'm well aware I have to watch out for endianess :) – David Mulder Mar 31 '14 at 19:25
  • @MadScienceDreams No, please no C-style casts. – Konrad Rudolph Mar 31 '14 at 19:35
  • This is called type punning as is actually [illegal](http://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule). You can *cast* the pointer via `reinterpret_cast` and it's guaranteed to work. You can't always *dereference* it, though. Your solution with bitshifting is OK and so is `memcpy` to a `uint32_t` object. Recommend you [read this](http://dbp-consulting.com/tutorials/StrictAliasing.html), too. – jrok Mar 31 '14 at 19:38
  • @KonradRudolph I understand the hate, but uh...this is C code, this is low-level, bit twiddling, teeth grinding, casting to the devil, assembly-inspecting, code. And we NEED it from time to time, cuz this is often the fastest way to do things. We can wrap the reinterpret_cast to make you feel better, but that won't change what we are doing! – IdeaHat Mar 31 '14 at 19:45
  • 1
    @MadScienceDreams Yes, I’m concerned with explicitness. `reinterpret_cast` is simply much more explicit in what it does. – Konrad Rudolph Mar 31 '14 at 23:38

4 Answers4

9

static_cast is meant to be used for "well-behaved" casts, such as double -> int. You must use reinterpret_cast:

uint32_t *starti = reinterpret_cast<uint32_t*>(&memory[164]);

Or, if you are up to it, C-style casts:

uint32_t *starti = (uint32_t*)&memory[164];
7

Yes, you can convert an unsigned char* pointer value to uint32_t* (using either a C-style cast or a reinterpret_cast) -- but that doesn't mean you can necessarily use the result.

The result of such a conversion might not point to an address that's properly aligned to hold a uint32_t object. For example, an unsigned char* might point to an odd address; if uint32_t requires even alignment, you'll have undefined behavior when you try to dereference the result.

If you can guarantee somehow that the unsigned char* does point to a properly aligned address, you should be ok.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
0

I am used to BDS2006 C++ but anyway this should work fine on other compilers too

char memory[164];
int *p0,*p1,*p2;
p0=((int*)((void*)(memory)));    // p0 starts from start
p1=((int*)((void*)(memory+64))); // p1 starts from 64th char
p2=((int*)((void*)(&memory[64]))); // p2 starts from 64th char
Spektre
  • 49,595
  • 11
  • 110
  • 380
0

You can use reinterpret_cast as suggested by faranwath but please understand the risk of going that route.

The value of what you get back will be radically different in a little endian system vs a big endian system. Your method will work in both cases.

R Sahu
  • 204,454
  • 14
  • 159
  • 270