2

I have this array of bytes, that I need to convert to an array of unsigned ints. Also the function (btea) that needs it, seems to need a pointer.

I'm currently using reinterpret_cast which seems to work, but I'd like to know how/why. I'm pretty new to C. It also seems kind of dirty. I could use a for loop, and bitshift everything into a separate int array variable, but that seems wasteful.

uint8_t data[] = {1,2,3,4,5,6,7,8};//can be any multiple of 4 bytes

btea(reinterpret_cast<uint32_t*>(data), sizeof(data)/4, encryption_key);

radio.write(data, sizeof(data));

...

void btea(uint32_t *v, int n)
{
  ...
}

Any pointers (pun intended) are much appreciated.

3

@mpflaga's answer gives a great alternative, but I thought I'd explain why your code works (grossly simplified).

All the reinterpret cast does is let the compiler know how wide of a variable it assumes is in each element of the array. When you access data[1], it uses one byte at an offset of one byte from data[0]. When you cast to uint32_t and access data[1], it uses 4 bytes at an offset of 4 bytes.

If your memory looks like this (each square is one byte)...

enter image description here

...before the cast you are interpreting it as the top layout, after the cast you interpret it as the bottom layout. It's still exactly the same in memory, you're just telling the compiler to use it differently. The reason that using a union is better is that it is safer. Your code would read garbage after the end of the array if its length wasn't divisible by 4.

One other quick note, be careful with the sizeof() operator on arrays - it always gives the length in bytes regardless of the element size.

  • about the sizeof() I usually employ "#define LENGTH_OF_ARRAY(x) ((sizeof(x)/sizeof(x[0])))". Noting it is the size of the whole array divided by the size of an individual element. – mpflaga Apr 6 '15 at 13:46
  • Great explanation. But what about the * in reinterpret_cast<uint32_t*>. Why doesn't it reinterpret the array-data as a pointer? – Gerben Apr 7 '15 at 10:42
  • 1
    @Gerben - That's because they both refer to the same memory location. data[0] and *data are both the equivalent, but use different semantics. In fact, data[1] and *data + 1 are also equivalent. The main difference to keep in mind is that when you declare and array like uint8_t data[7]; the compiler reserves 8 contiguous bytes of RAM and a memory address, but when if you declare uint8_t* data, it only gets you an address. There's a decent tutorial here that gives more justice to the concept than I can in a comment. – Comintern Apr 7 '15 at 12:16
3

I prefer to use unions. example:

union fourbyte {
  uint32_t dword;
  uint16_t word[2];
  uint8_t  byte[4];
};

union fourbyte val;

val.dword = 0x03020100;

Serial.println(val.byte[0], HEX);
Serial.println(val.byte[1], HEX);
Serial.println(val.byte[2], HEX);
Serial.println(val.byte[3], HEX);

Serial.println(val.word[0], HEX);
Serial.println(val.word[1], HEX);

Serial.println(val.dword, HEX);
  • My byte array is of length 8. So I could do something like union eightbyte {uint32_t dword[2]; uint16_t word[4]; uint8_t byte[8];};. Variable length arrays seem be impossible using this method. – Gerben Apr 7 '15 at 10:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.