Reputation: 35
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
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
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