1

I need efficient way to cast part of array to variable. Let's suppose array is defined as this:

unsigned char bytes[240];

now, I need to get uint32_t value from somewhere in the array, something like this:

uint32_t * word = reinterpret_cast<uint32_t *>(bytes[4]);

Which I think will get me second word in the array right? My question is, is this safe and portable (windows, linux on x86 & x86_64, os x would be nice, don't care about arm, ia-64 etc).

12
  • yes, yes. why don't you simply compile it and try it out? Commented Apr 22, 2014 at 11:37
  • 5
    should be uint32_t * word = reinterpret_cast<uint32_t *>(&bytes[4]); otherwise you're casting the value of bytes[4] into a pointer. Commented Apr 22, 2014 at 11:37
  • 1
    The problem is, it's not portable across different machine architectures or data coming from network connections (also see Endianess) Commented Apr 22, 2014 at 11:38
  • @πάνταῥεῖ what you said is correct, but the OP only seem to care about intel machines. Commented Apr 22, 2014 at 11:42
  • 2
    Care also to alignment issues. Commented Apr 22, 2014 at 11:53

3 Answers 3

4

You should use memcpy. This portably ensures that there are no alignment or strict aliasing problems. If no copy is needed, compilers are often smart enough to figure this out and directly reference the data in the array:

uint32_t value;
memcpy(&value, &bytes[4], sizeof value);
//Modify value:
//...
//Copy back to array:
memcpy(&bytes[4], &value, sizeof value);
Sign up to request clarification or add additional context in comments.

1 Comment

How efficient is memcpy for small sizes? I have only used it for copying large blocks but maybe I should be using it for small blocks as well.
2

What you do does not violate strict aliasing rules because you cast to/from a char type pointer. In the standard, pointers to char types are the only exception from the strict aliasing rules.

As others have pointed out, you can run into the problem of alignment when you cast a char* to a larger type. You can either work around this by doing the alignment yourself, or just use memcpy() as Mankarse suggests.

But even the memcpy() approach is subject to byte order problems: If you've written your program on a little endian machine (x86 for example), it will likely crash on a big endian machine (ARM for example), and vice versa.

So, if you want to write portable code, you need to use a byte order that you specify. You can easily do so using the bit shift operators:

int32_t read_word_le(signed char* bytes) {
    return (int32_t)bytes[0] +
        ((int32_t)bytes[1] << 8) +
        ((int32_t)bytes[2] << 16) +
        ((int32_t)bytes[3] << 24);
}

int32_t read_word_be(signed char* bytes) {
    return (int32_t)bytes[3] +
        ((int32_t)bytes[2] << 8) +
        ((int32_t)bytes[1] << 16) +
        ((int32_t)bytes[0] << 24);
}

1 Comment

Good point about byte order problems. My answer is only valid if the data in the array was originally put there by the same program (on the same platform with the same compiler). This is often a valid assumption, but it is obviously false if the data is being moved around a network or otherwise persisted between program runs.
0

I would avoid indexing on the char if I know what is in the buffer. If it is indeed an array of int, cast first and index after for clarity. If you want the second 32 bits integer in the array:

uint32_t * words = reinterpret_cast(bytes); uint32_t second = words[1];

It is hard to answer about portability as you don't provide much information on the use case. As long as the data in the bytes buffer is produced and used on the same machine, the code is portable (and would be using simply int). Things become messy when you exchange data produced on a different architecture.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.