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

有帮助吗?

解决方案

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

其他提示

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

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.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top