How to properly combine 4 bytes to make a float (single) - c

I have the following:
payload.data[i].data = (buf[8] << 24) | (buf[9] << 16) | (buf[10] << 8) | (buf[11]);
note: payload.data[i].dataif of type float.
Using this: printf("test:%X%X%X%X", buf[8], buf[9], buf[10], buf[11]);, I have confirmed that the buffer contains #42C78A3D or DEC 99.77 (roughly).
This: printf("Float value:%f", payload.data[i].data prints out 1120373248.00, which is DEC for #42C78A00
It seems to me that for some reason, buf[11] is coming up empty.
Here is a more complete view of my code:
int i = 0;
int j = 0;
struct sensor_payload payload;
payload.key = (buf[0] << 8) | buf[1];
payload.id = (buf[2] << 8) | buf[3];
payload.type = (buf[4] << 8) | buf[5];
payload.fields = buf[6];
for(i = 0, j = 0; i < payload.fields; i++, j = j +33){
payload.data[i].data_type = buf[j+7];
payload.data[i].data = (buf[j+8] << 24) | (buf[j+9] << 16) | (buf[j+10] << 8) | (buf[j+11]);
slog(0, SLOG_DEBUG, "test:%X%X%X%X", buf[8], buf[9], buf[10], buf[11]);
}
payload.valid = true;
return payload;
and the definitions:
struct sensor_data{
uint8_t data_type;
float data;
};
struct sensor_payload{
uint16_t key, id, type;
uint8_t fields;
struct sensor_data data[4];
bool valid;
};

There's a lot in you code which is unclear. However, the only discrepancy I see is that you're putting index-offset entries into your data (notice the j+x pattern):
(buf[j+8] << 24) | (buf[j+9] << 16) | (buf[j+10] << 8) | (buf[j+11])
while printing non-offset entires:
slog(0, SLOG_DEBUG, "test:%X%X%X%X", buf[8], buf[9], buf[10], buf[11])
Technically, data you're printing and putting into the float is only the same for i==0.

Related

Assigning an array of structs in another sruct

I have the following code:
struct sensor_data{
uint8_t data_type;
signed int data_left;
uint8_t data_right;
};
struct sensor_payload{
uint16_t key, id, type;
uint8_t fields;
struct sensor_data data[4];
bool valid;
};
As you can see, struct sensor_payload has a struct sensor_data[4] inside of it. Basically, an array of structs within a struct.
When I try to assign it:
uint16_t rcvd_key = (buf[0] << 8) | buf[1];
uint16_t rcvd_id = (buf[2] << 8) | buf[3];
uint16_t rcvd_type = (buf[4] << 8) | buf[5];
uint8_t rcvd_fields = buf[6];
struct sensor_data rcvd_data[4];
while(i <= (rcvd_fields)){
rcvd_data[i].data_type = buf[j+7];
rcvd_data[i].data_left = buf[j+8];
rcvd_data[i].data_right = buf[j+9];
i++;
j = j + 3;
}
struct sensor_payload payload;
payload.key = rcvd_key;
payload.id = rcvd_id;
payload.type = rcvd_type;
payload.data = rcvd_data; <<LINE WITH ERROR
payload.valid = true;
I get: assignment to expression with array type
Not even sure what the error means...
I tried this:
payload.data[0] = rcvd_data[0];
without changing ANY of the other code, and it compiles, but I am worried it's not the cleanest way to do it... Or the right way...
I have a feeling this problem is due to me not fully understanding pointers, or not seeing their use in this situation.
Arrays can't be copied using the assignment operator =, so they can't be assigned to.Use
A for-loop:
for (size_t i = 0; i < sizeof(payload.data) / sizeof(*(payload.data)); ++i)
payload.data[i] = rcvd_data[i];
Or memcpy:
memcpy(payload.data, rcvd_data, sizeof(payload.data));
instead.
You can save yourself some time and trouble but writing the data directly into the payload structure, like this
struct sensor_payload payload;
payload.key = (buf[0] << 8) | buf[1];
payload.id = (buf[2] << 8) | buf[3];
payload.type = (buf[4] << 8) | buf[5];
payload.fields = buf[6];
j = 7;
for ( i = 0; i < 4 && i < payload.fields; i++ )
{
payload.data[i].data_type = buf[j++];
payload.data[i].data_left = buf[j++];
payload.data[i].data_right = buf[j++];
}
payload.valid = true;

Byte array to Decimal

i have a byte array (64-bit unsigned integer) :
byte array[8] = { 0x01,0xc9,0x98,0x57,0xd1,0x47,0xf3,0x60 }
i want to translate it into decimal..
when i'am using the calculator windows the result is :
128801567297500000
i don't find a way to do it in winapi or C ..
Any help is appreciated.
for a 4 bytes array i use the working code below
BYTE array[4] = { 0xC3,0x02,0x00,0x00 };
printf("Result : %d\n",(array[0]) | (array[1]) <<8 |(array[2]) <<16 | (array[3]) <<24 );
Result : 707
Cast the bytes to 64bit before the shifting. Currently they are implicitly promoted to int, which is a 32bit data type.
Assuming you use stdint:
uint64_t result = ((uint64_t)b[0]) | ((uint64_t)b[1] << 8) | ((uint64_t)b[2] << 16) | ((uint64_t)b[3] << 24) | ((uint64_t)b[4] << 32) | ((uint64_t)b[5] << 40) | ((uint64_t)b[6] << 48) | ((uint64_t)b[7] << 56);
or in reverse order (array is little endian; this will get the result you're seeing in windows calculator):
uint64_t result = ((uint64_t)b[7]) | ((uint64_t)b[6] << 8) | ((uint64_t)b[5] << 16) | ((uint64_t)b[4] << 24) | ((uint64_t)b[3] << 32) | ((uint64_t)b[2] << 40) | ((uint64_t)b[1] << 48) | ((uint64_t)b[0] << 56);
well, you can use
sprintf() to print the positional hex values to a string.
convert that string to decimal using strtoll() using base 16.
Sample code:
#include <stdio.h>
#include <stdlib.h>
#define SIZE 128
int main()
{
char array[8] = { 0x01,0xc9,0x98,0x57,0xd1,0x47,0xf3,0x60 };
char arr[SIZE] = {0};
int i = 0;
unsigned long long res = 0;
for (i = 0; i < 8; i++)
sprintf((arr + (i * 2)), "%2x", (array[i] & 0xff));
printf("arr is %s\n", arr);
res = strtoll(arr, NULL, 16);
printf("res is %llu\n", res);
return 0;
}
int i;
byte array[8] = { 0x01,0xc9,0x98,0x57,0xd1,0x47,0xf3,0x60 };
unsigned long long v;
//Change of endian
for(i=0;i<4;++i){
byte temp = array[i];
array[i] = array[7-i];
array[7-i] = temp;
}
v = memcpy(&v, array, sizeof(v));//*(unsigned long long*)array;
printf("%llu ", v);

Merging uint8 array into uint64 error

I am trying out this code where I first split a uint64 number into an array of uint8, followed by merging the said array back into the original number.
However when I attempt to print out the number out, it seems to return the max value of uint64.
uint8 buf[8];
uint64 test = 123456789012;
uint64 out = 0;
Uint64toUint8Arr(buf, test, 0);
out = Uint8ArrtoUint64(buf, 0);
std::cout << "out is " << out << std::endl;
where my functions are defined as:
void Uint64toUint8Arr (uint8* buf, uint64 var, uint32 lowest_pos)
{
buf[lowest_pos] = (var & 0x00000000000000FF) >> 0 ;
buf[lowest_pos+1] = (var & 0x000000000000FF00) >> 8 ;
buf[lowest_pos+2] = (var & 0x0000000000FF0000) >> 16 ;
buf[lowest_pos+3] = (var & 0x00000000FF000000) >> 24 ;
buf[lowest_pos+4] = (var & 0x000000FF00000000) >> 32 ;
buf[lowest_pos+5] = (var & 0x0000FF0000000000) >> 40 ;
buf[lowest_pos+6] = (var & 0x00FF000000000000) >> 48 ;
buf[lowest_pos+7] = (var & 0xFF00000000000000) >> 56 ;
}
uint64 Uint8ArrtoUint64 (uint8* var, uint32 lowest_pos)
{
return (var[lowest_pos+7] << 56) |
(var[lowest_pos+6] << 48) |
(var[lowest_pos+5] << 40) |
(var[lowest_pos+4] << 32) |
(var[lowest_pos+3] << 24) |
(var[lowest_pos+2] << 16) |
(var[lowest_pos+1] << 8) |
(var[lowest_pos] << 0);
}
My question is that did I go wrong in either the way I split or merge the uint64 number? I did a similar function for a uint32 type and it seemed to be ok.
The problem is that you're shifting uint8 in Uint8ArrtoUint64() function on more than 8 bits. As far as I know it's undefined behavior. Anyway, return value is uint8, so you're "or'ing" eight times eight uint8 numbers and finally you have only uint8 number, not uint64! You need to cast them to uint64 first, then shift.
uint64 Uint8ArrtoUint64 (uint8* var, uint32 lowest_pos)
{
return (((uint64)var[lowest_pos+7]) << 56) |
(((uint64)var[lowest_pos+6]) << 48) |
(((uint64)var[lowest_pos+5]) << 40) |
(((uint64)var[lowest_pos+4]) << 32) |
(((uint64)var[lowest_pos+3]) << 24) |
(((uint64)var[lowest_pos+2]) << 16) |
(((uint64)var[lowest_pos+1]) << 8) |
(((uint64)var[lowest_pos]) << 0);
}
Note: As #interjay noted, shifting operation on uint8 will actually give us uint32. I'm not sure about that, but anyway it's better to mention it.

How to concatenate an int in c

So I have this code
char str[80] = "192.168.12.142";
char string[80];
char s[2] = ".";
char *token;
int val[4];
int counter=0;
/* get the first token */
token = strtok(str, s);
/* walk through other tokens */
while( token != NULL ){
val[counter] = atoi(token);
token = strtok(NULL, s);
counter++;
}
sprintf(string,"%d.%d.%d.%d",val[0],val[1],val[2],val[3]);
puts(string);
Instead of concatenate it into an string, I want to concatenate it to an int concatenation, is there any possibly alternative?
First of all, what you seem to do is exactly what inet_aton is doing. You might consider using this function.
Regarding the concatenation you can write
int result = (val[3] << 24) | (val[2] << 16) | (val[1] << 8) | (val[0]);
or, for the opposite byte order:
int result = (val[0] << 24) | (val[1] << 16) | (val[2] << 8) | (val[3]);
You probably want
(((((val[0] << 8) + val[1]) << 8) + val[2]) << 8 ) + val[3]
Or equivalently
(val[0] << 24) | (val[1] << 16) | (val[2] << 8) | val[0]

word alignment on ARM?

How do I go about avoiding the compiler warning (warning: cast increases required alignment of target type) in the following code?
static int fill_color24 (VisVideo *video, VisColor *color)
{
int x, y;
uint32_t *buf;
uint8_t *rbuf = visual_video_get_pixels (video);
uint8_t *buf8;
int32_t cola =
(color->b << 24) |
(color->g << 16) |
(color->r << 8) |
(color->b);
int32_t colb =
(color->g << 24) |
(color->r << 16) |
(color->b << 8) |
(color->g);
int32_t colc =
(color->r << 24) |
(color->b << 16) |
(color->g << 8) |
(color->r);
for (y = 0; y < video->height; y++) {
buf = (uint32_t *) rbuf; // warning is for this line
for (x = video->width; x >= video->bpp; x -= video->bpp) {
*(buf++) = cola;
*(buf++) = colb;
*(buf++) = colc;
}
buf8 = (uint8_t *) buf;
*(buf8++) = color->b;
*(buf8++) = color->g;
*(buf8++) = color->r;
rbuf += video->pitch;
}
return VISUAL_OK;
}
I'm not sure you can. That function might return color array unaligned. You can't do anything to be able to read word from there.
You will have to read color by components (uint8_t) and then construct uint32_t from these by adding and shifting.

Resources