C - Store float to char array and reverse - c

Let's say I have this float:
float f;
And I want to store it in a char array:
char bytes[4];
And then reverse the array back to float.
Any help? Thanks in advance.
EDIT: Here is the code AND IT WORKS:
float amount = 0.01;
char array[sizeof(float)];
memcpy(array, &amount, sizeof(float));
float f;
char bytes[4] = {array[0], array[1], array[2], array[3]};
memcpy(&f, bytes, sizeof f);

Supposing that sizeof(float) is 4, you can copy the representation of the value of a float variable into a char array via memcpy:
#include <string.h>
void do_something(float f) {
char bytes[4];
memcpy(bytes, &f, 4);
// ...
}
You can reverse that operation (that is, copy the representation back) by calling memcpy() again, with the first two arguments reversed. In between, you can manipulate the bytes -- for example, to reverse them -- but in that case, the language does not speak to the float interpretation of the resulting byte sequence.

You can use memcpy, but it is good to include a _Static_assert to check the sizes:
#include <stdio.h>
#include <string.h>
int main(void)
{
float f = 10./7;
char bytes[4];
// Check that float is the same size as the array we provide.
_Static_assert(sizeof f == sizeof bytes, "float mus be four bytes.");
// Copy bytes from the float to the array.
memcpy(bytes, &f, sizeof bytes);
// Show the bytes.
for (size_t i = 0; i < sizeof bytes; ++i)
printf("Byte %zu is 0x%02x.\n", i, (unsigned char) bytes[i]);
// Copy the bytes from the array to another float.
float g;
memcpy(&g, bytes, sizeof g);
// Show the resulting float.
printf("g = %g.\n", g);
}

To convert float to char array sprintf
To convert char array to float atof
#include <stdio.h>
#include <stdlib.h>
int main()
{
char array[10];
float val;
sprintf(array, "%f", 3.123);
val = atof(array);
printf("%s\n%f", array, val);
return 0;
}
Output
3.123000
3.123000

memcpy is a built-in function requiring the header "string.h". Depending on your application scenario, if you want to avoid the use of memcpy plus your char array is 4-byte aligned, here is my preferred way based on static casting in gcc-like compilers.
Copy amount (float) to array (char*)
float amount = 0.01;
char array[4] __attribute__((aligned(4)));
*((float *)array) = amount;
Copy bytes (char*) to f (float)
float f;
char bytes[4] __attribute__((aligned(4)));
f = *((float *) bytes);
Alternatively, here is one more way that I believe will work under any compilers, regardless of byte alignment:
First, define a dummy struct with four bytes (a float takes four bytes. or alternatively, use sizeof(float) in place of 4).
typedef struct {char fourBytes[4]; } FourBytes ;
Use it as follows:
float amount = 0.01;
char array[4] ;
// copy from amount to array
*((FourBytes *)array) = *((FourBytes *) (&amount));
// copy from array to amount
*((FourBytes *) (&amount)) = *((FourBytes *)array) ;
From a functional perspective, a third alternative may be just to use a union structure:
union DATA
{
float f;
char array[4];
}; // array is forced to 4-byte aligned
Use it as follows:
union DATA data1;
union DATA data2;
// copy data between the two
data1.f = data2.f

Related

Recoding printf %p with write function, no printf

I am currently working on a task where I need to print the address of a variable. It would be easy to use printf %p but I am only allowed to use write from unistd.
I tried casting the pointer in to an unsigned integer and uintptr_t and then converting it into a hexadecimal number. With uintptr_t it works but with an unsigned integer it only prints half of the address. Maybe someone can explain me why this is the case?
I also saw some solutions using ">>" and "<<" but I didn't get why that works. It would be nice if someone can explain a solution using "<<" and ">>" step by step, because I am not sure if I am allowed to use uintptr_t.
this is the code I use to cast it into a unsigned int / unitptr_t / unsigned long long (I know that ft_rec_hex is missing leading 0's):
void ft_rec_hex(unsigned long long nbr)
{
char tmp;
if (nbr != 0)
{
ft_rec_hex(nbr / 16);
if (nbr % 16 < 10)
tmp = nbr % 16 + '0';
else
tmp = (nbr % 16) - 10 + 'a';
write(1, &tmp, 1);
}
}
int main(void)
{
char c = 'd';
unsigned long long ui = (unsigned long long)&c;
ft_rec_hex(ui);
}
It looks like only half of the address is printed because the "unsigned integer" you used has only half size of uintptr_t. (note that uintptr_t is an unsigned integer type)
You can use an array of unsigned char to store data in a pointer variable and print that to print full pointer withput uintptr_t.
Using character types to read objects with other type is allowed according to strict aliasing rule.
#include <stdio.h>
#include <unistd.h>
void printOne(unsigned char v) {
const char* chars = "0123456789ABCDEF";
char data[2];
data[0] = chars[(v >> 4) & 0xf];
data[1] = chars[v & 0xf];
write(1, data, 2);
}
int main(void) {
int a;
int* p = &a;
/* to make sure the value is correct */
printf("p = %p\n", (void*)p);
fflush(stdout);
unsigned char ptrData[sizeof(int*)];
for(size_t i = 0; i < sizeof(int*); i++) {
ptrData[i] = ((unsigned char*)&p)[i];
}
/* print in reversed order, assuming little endian */
for (size_t i = sizeof(int*); i > 0; i--) {
printOne(ptrData[i - 1]);
}
return 0;
}
Or read data in a pointer variable as unsigned char array without copying:
#include <stdio.h>
#include <unistd.h>
void printOne(unsigned char v) {
const char* chars = "0123456789ABCDEF";
char data[2];
data[0] = chars[(v >> 4) & 0xf];
data[1] = chars[v & 0xf];
write(1, data, 2);
}
int main(void) {
int a;
int* p = &a;
/* to make sure the value is correct */
printf("p = %p\n", (void*)p);
fflush(stdout);
/* print in reversed order, assuming little endian */
for (size_t i = sizeof(int*); i > 0; i--) {
printOne(((unsigned char*)&p)[i - 1]);
}
return 0;
}
It would be easy to use printf %p but I am only allowed to use write from unistd.
Then form a string and print that.
int n = snprintf(NULL, 0, "%p", (void *) p);
char buf[n+1];
snprintf(buf, sizeof buf, "%p", (void *) p);
write(1, buf, n);
Using a pointer converted to an integer marginally reduces portability and does not certainly form the best textual representation of the pointer - something implementation dependent.
With uintptr_t it works but with an unsigned integer it only prints half of the address.
unsigned is not specified to be wide enough to contain all the information in a pointer.
uintptr_t, when available (very common), can preserve most of that information for void pointers. Good enough to round-trip to an equivalent pointer, even if in another form.

Double from unsigned int[2]?

I have a 64-bit number written as two 32-bit unsinged ints: unsigned int[2]. unsigned int[0] is MSB, and unsigned int[1] is LSB. How would I convert it to double?
double d_from_u2(unsigned int*);
memcpy it from your source array to a double object in proper order. E.g. if you want to swap the unsigned parts
unsigned src[2] = { ... };
double dst;
assert(sizeof dst == sizeof src);
memcpy(&dst, &src[1], sizeof(unsigned));
memcpy((unsigned char *) &dst + sizeof(unsigned), &src[0], sizeof(unsigned));
Of course, you can always just reinterpret both source and destination objects as arrays of unsigned char and copy them byte-by-byte in any order you wish
unsigned src[2] = { ... };
double dst;
unsigned char *src_bytes = (unsigned char *) src;
unsigned char *dst_bytes = (unsigned char *) &dst;
assert(sizeof dst == 8 && sizeof src == 8);
dst_bytes[0] = src_bytes[7];
dst_bytes[1] = src_bytes[6];
...
dst_bytes[7] = src_bytes[0];
(The second example is not intended to be equivalent to the first one.)
There are several ways to copy the bits of your two integers into an object of type double.
At the lowest level, you can convert your input pointer to a [unsigned] char *, create a [unsigned] char * to the first byte of the return value, and copy between those by whatever means you choose. This provides you every opportunity to adjust byte order as may be needed -- for example, although your array is ordered most-significant word first, the order of the bytes within those words might not be what you need.
In the event that you need the bytes to be transferred into your double most-significant byte first, and that you do not want to depend on the machine byte order, you might do this:
double d_from_u2(unsigned int *in) {
double result;
unsigned char *result_bytes = (unsigned char *) &result;
for (int i = 0; i < 4; i++) {
result_bytes[i] = in[0] >> (24 - 8 * i);
result_bytes[i + 4] = in[1] >> (24 - 8 * i);
}
return result;
}
Using arithmetic (shifts, in this case) allows you to operate on the numeric values of the input independently of details of numeric representation.
Here is a solution that works without memcpybut using union:
#include "stdio.h"
#include "stdint.h"
double d_from_u2(unsigned int* v) {
union {
int32_t x[2];
int64_t y;
} u = { .x = { v[1], v[0] }};
printf("%llu\n", u.y); // 1311768467463794450
return (double)u.y;
}
int main(void) {
int32_t x[2];
x[0] = 0x12345678;
x[1] = 0x9abcef12;
printf("%f\n", d_from_u2(x)); // 1311768467463794432.000000
return 0;
}
See demo. In initializes the array int32_t[2] in the union and uses the int64_t to convert it to a double. The order of the initialization depends on which machine (little or big endian) it runs or where the values comes from (1 first).

How to convert byte array (containing hex values) to decimal

I am writing some code for an Atmel micro-controller. I am getting some data via Uart, and I store these hex values into an array.
Suppose the elements of the array are: 1F, 29, and 3C.
I want to have one hex number like 0x1F293C, and convert it to a decimal number. So, I want to get “2042172” at the end.
The array could have n elements, so I need a general solution.
Thank you.
sprintf(buffer, "%d", (((unsigned)array[0])<<16)+(((unsigned)array[1])<<8)+(unsigned)array[2];
this will write the hex values in array to buffer as readable string in decimal representation.
assuming sizeof(int)=4
If you have a array of characters like "0x1F293C" and want to convert it to int try this code:
char receivedByte[] = "0x1F293C";
char *p;
int intNumber = strtol(receivedByte, &p, 16);
printf("The received number is: %ld.\n", intNumber);
If data is declared as stated in the comments (char data[]={0x1F, 0x29, 0x3C}), you can run this program.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char receivedByte[9], *p;
char data[] = { 0x1F, 0x29, 0x3C };
sprintf(receivedByte, "0x%X%X%X", data[0], data[1], data[2]);
int intNumber = strtol(receivedByte, &p, 16);
printf("The received number is: %ld.\n", intNumber);
return 0;
}
If the input consists of n bytes and are stored starting from a pointer array, you can add the values up in the order you "received" them - i.e., in the order they are written in the array.
unsigned int convertToDecimal (unsigned char *array, int n)
{
unsigned int result = 0;
while (n--)
{
result <<= 8;
result += *array;
array++;
}
return result;
}
Note that your sample input contains 3 bytes and you want a "general solution for n bytes", and so you may run out of space really fast. This function will only work for 0..4 bytes. If you need more bytes, you can switch to long long (8 bytes, currently).
For longer sequences than that you need to switch to a BigNum library.
#include <stdio.h>
int main(){
char data[] = {0x1F, 0x29, 0x3C};
int i, size = sizeof(data);
unsigned value = 0;
for(i=0;i<size;++i)
value = value * 256 + (unsigned char)data[i];
printf("0x%X %d\n", value, (int)value);
return 0;
}

Copying Ascii Value to int

I have code snippet as Below
unsigned char p = 0;
unsigned char t[4] = {'a','b','c','d'};
unsigned int m = 0;
for(p=0;p<4;p++)
{
m |= t[p];
printf("%c",m);
m = m << 2;
}
Can anybody help me in solving this. consider i have an ascii value abcd stored in an array t[]. I want to store the same value in 'm'. m is my unsigned int variable . which stores the major number. when i copy the array into m & print m . m should print abcd. can anybody state their logic.
As I understand you, you want to encode the 4 characters into a single int.
Your bit shifting is not correct. You need to shift by 8 bits rather than 2. You also need to perform the shifting before the bitwise or. Otherwise you shift too far.
And it makes more sense, in my view, to print the character rather than m.
#include <stdio.h>
int main(void)
{
const unsigned char t[4] = {'a','b','c','d'};
unsigned int m = 0;
for(int p=0;p<4;p++)
{
m = (m << 8) | t[p];
printf("%c", t[p]);
}
printf("\n%x", m);
return 0;
}
Why not just look at the t array as an unsigned int?:
unsigned int m = *(unsigned int*)t;
Or you could use an union for nice access to the same memory block in two different ways, which I think is better than shifting bits manually.
Below is an union example. With unions, both the t char array and the unsigned int are stored in the same memory blob. You get a nice interface to each, and it lets the compiler do the bit shifting (more portable, I guess):
#include <stdio.h>
typedef union {
unsigned char t[4];
unsigned int m;
} blob;
int main()
{
blob b;
b.t[0]='a';
b.t[1]='b';
b.t[2]='c';
b.t[3]='d';
unsigned int m=b.m; /* m holds the value of blob b */
printf("%u\n",m); /* this is the t array looked at as if it were an unsignd int */
unsigned int n=m; /* copy the unsigned int to another one */
blob c;
c.m=n; /* copy that to a different blob */
int i;
for(i=0;i<4;i++)
printf("%c\n",c.t[i]); /* even after copying it as an int, you can still look at it as a char array, if you put it into the blob union -- no manual bit manipulation*/
printf("%lu\n", sizeof(c)); /* the blob has the bytesize of an int */
return 0;
}
Simply assign t[p] to m.
m = t[p];
this will implicitly promote char to unsigned int.
unsigned char p = 0;
unsigned char t[4] = {'a','b','c','d'};
unsigned int m = 0;
for(p=0;p<4;p++)
{
m = t[p];
printf("%c",m);
}

Understanding unsigned 0 in C

I am trying to understand number representation in C.
I am working on a code segment which looks like the one below.
#include <stdio.h>
#include <string.h>
typedef unsigned char *byte_pointer;
void show_bytes(byte_pointer start, int len)
{
int i;
for (i = 0; i < len; i++)
printf(" %.2x", start[i]);
printf("\n");
}
void show_int(int x) {
show_bytes((byte_pointer) &x, sizeof(int));
}
void show_unsigned(short x) {
show_bytes((byte_pointer) &x, sizeof(unsigned));
}
int main(int argc,char*argv[])
{
int length=0;
unsigned g=(unsigned)length;// i aslo tried with unsigned g=0 and the bytes are the same
show_unsigned(g);
show_int(length);
printf("%d",g);//this prints 0
return 0;
}
Here, show_unsigned() and show_int() prints the byte representations of the variables specified as arguments.For int length the byte representation is all zeroes as expected, but for unsigned g, the byte representation is 00 00 04 08.But when I print g with a %d, I get 0(so i suppose the numeric value is interpreted as 0 )
Please could somebody explain how this is happening.
In:
void show_unsigned(short x) {
show_bytes((byte_pointer) &x, sizeof(unsigned));
}
You declared the argument short x which is smaller than int x so you ignored some of the 00 and your print function is displaying adjacent garbage.
You're reading sizeof(unsigned) bytes in a short. short isn't guaranteed to be the same size as unsigned, hence, when reading the bytes next to your short, garbage data is read.
To fix this, either pass your argument as an unsigned, or when using sizeof, use sizeof(short).
what you are doing doesn't make any sense, particularly with the type conversions that you have occurring. Someone else already pointed out my point about the conversion to short
Rather than writing an absurd number of functions try doing this
void show_bytes( void *start, unsigned int len ) {
unsigned char* ptr = (unsigned char *) start;
unsigned int i = 0;
for ( i = 0; i < len; ++i, ++ptr ) {
printf( " %.2x", ptr[0] );
}
}
Instead of calling as you had been just call it like:
show_bytes( (void *)&x, sizeof(x));
And if thats too much typing make a macro out of that. now it works for any type you come up with.

Resources