shams alsham
shams alsham

Reputation: 35

Converting bytes array to integer

I have a 4-byte array (data) of type uint8_t, which represents a speed data integer. I'm trying to cast this array to uint32_t integer (speed), multiply this speed by 10 and then restore it back to the 4-byte array (data). The data format is clear in the code below. I always get the error:

"assignment to expression with array type"

The code:

volatile uint8_t data[4] = {0x00 , 0x00, 0x00, 0x00};
volatile uint32_t speed;
speed=( uint32_t)*data;
speed=speed*10;
data=(uint8_t*)speed;

Upvotes: 2

Views: 1410

Answers (2)

Lundin
Lundin

Reputation: 213408

Your code doesn't work because during data=(uint8_t*)speed; you don't get a "lvalue" for data, you just get an array type which can't be used in assignment or any form of arithmetic. Similarly, speed=( uint32_t)*data; is a bug because that only gives you the first item in the array.

The only correct way you should do this:

volatile uint8_t data[4] = {0x00 , 0x00, 0x00, 0x00};
volatile uint32_t speed;

speed = (uint32_t)data[0] << 24 |
        (uint32_t)data[1] << 16 |
        (uint32_t)data[2] <<  8 |
        (uint32_t)data[3] <<  0;

speed=speed*10;

data[0] = (uint8_t) ((speed >> 24) & 0xFFu);
data[1] = (uint8_t) ((speed >> 16) & 0xFFu);
data[2] = (uint8_t) ((speed >>  8) & 0xFFu);
data[3] = (uint8_t) ((speed >>  0) & 0xFFu);

This is 100% portable and well-defined code. No implicit promotions take place. This code does not rely on endianess or other implementation-defined behavior. Why write code that does, when you can write code that doesn't?

Upvotes: 5

Garf365
Garf365

Reputation: 3707

To be safe according endianess, portable and secure, you should recreate your data:

speed = ((uint32_t)data[0]) << 24 
      | ((uint32_t)data[1]) << 16 
      | ((uint32_t)data[2]) << 8 
      | ((uint32_t)data[3]);

or

speed = ((uint32_t)data[3]) << 24 
      | ((uint32_t)data[2]) << 16 
      | ((uint32_t)data[1]) << 8 
      | ((uint32_t)data[0]);

Choose solution according position of most significant byte


You get an "assignment to expression with array type" error because you can't assign directly an array: data=(uint8_t*)speed; is totally forbidden in C, you definitively can't have an array for lvalue. You have to do inverse operation:

data[0] = (uint8_t)((speed >> 24) & 0x00FF);
data[1] = (uint8_t)((speed >> 16) & 0x00FF);
data[2] = (uint8_t)((speed >> 8) & 0x00FF);
data[3] = (uint8_t)(speed & 0x00FF);

or, according position of most significant byte:

data[3] = (uint8_t)((speed >> 24) & 0x00FF);
data[2] = (uint8_t)((speed >> 16) & 0x00FF);
data[1] = (uint8_t)((speed >> 8) & 0x00FF);
data[0] = (uint8_t)(speed & 0x00FF);

EDIT

Don't use cast or memcpy as mention in commentaries and original answer: in addition of non portability issues, you will have security issues, according alignment restrictions and aliasing rules on some platform, compiler can generate incorrect code - thanks to user694733 | see here - thanks to Lundin

    speed = *((uint32_t *)data); // DANGEROUS NEVER USE IT
    *((uint32_t *)data) = speed; // DANGEROUS NEVER USE IT

Upvotes: 6

Related Questions