Floats to chars and chars to floats

K

Kosio

-Hello,

I'm looking for a way to deconstruct a (32 bit) float value to four
(8 bit) char values. I then need a way to take those four (8 bit) char
values and construct a (32 bit) float value.

The reason I ask is that I am sending things across an rs485 serial
network, and the protocol is set up to send byte by byte. It sends one
(8 bit) char at a time. I would like to send a float across this
network in the form of four chars...

Any ideas, suggestions? (Btw: this is a C compiler for a cypress
microcontroller, not a C++ compiler)

Thanks,
Aaron
 
S

Simon Biber

Kosio said:
-Hello,

I'm looking for a way to deconstruct a (32 bit) float value to four
(8 bit) char values. I then need a way to take those four (8 bit) char
values and construct a (32 bit) float value.

The reason I ask is that I am sending things across an rs485 serial
network, and the protocol is set up to send byte by byte. It sends one
(8 bit) char at a time. I would like to send a float across this
network in the form of four chars...

Any ideas, suggestions? (Btw: this is a C compiler for a cypress
microcontroller, not a C++ compiler)

Firstly, I hope you understand the difference between a byte and an
octet. In C, a byte must have at least 8 bits, but may have more. The
number of bits in a byte can be determined at compile-time by using the
macro CHAR_BIT after including the header <limits.h>.

From your description, it sounds like this function should send 8-bit
chunks, even if CHAR_BIT is more than 8.

#include <limits.h>

void serialise_float(float value)
{
unsigned char *p = (unsigned char *)&value;
size_t i, j;
for(i = 0; i < sizeof value; i++) {
for(j = 0; j < (CHAR_BIT+7)/8; j++)
send(p >> j * 8 & 0xFF);
}
}

Replace "send" with the name of the function you need to use to send a
byte over this serial connection.

It will send the float in the native representation, char by char, and
send each char in 8-bit octets, least significant octet first.

Writing a function to deserialise this data on another machine requires
you to know the exact binary format of the float data, and what the
value of CHAR_BIT was on the original machine.

If you can assume that CHAR_BIT was 8, and that 'float' has the same
binary format on each machine, then a function like this should suffice:

float deserialise_float(void)
{
float value;
unsigned char *p = (unsigned char *)&value;
size_t i;

for(i = 0; i < sizeof value; i++)
{
p = receive();
}

return value;
}

Replacing "receive" with the name of the function that receives a byte
from the serial connection.

My code is untested and is only intended to serve as an example.
 
J

John Bode

Kosio said:
-Hello,

I'm looking for a way to deconstruct a (32 bit) float value to four
(8 bit) char values. I then need a way to take those four (8 bit) char
values and construct a (32 bit) float value.

The reason I ask is that I am sending things across an rs485 serial
network, and the protocol is set up to send byte by byte. It sends one
(8 bit) char at a time. I would like to send a float across this
network in the form of four chars...

Any ideas, suggestions? (Btw: this is a C compiler for a cypress
microcontroller, not a C++ compiler)

Thanks,
Aaron

The following assumes that both ends of the communication line are the
same byte sex and use the same representation for float:

/* sender */
float theValue;
unsigned char *bytes = (unsigned char *)&theValue;
int i;
for (i = 0; i < sizeof theValue; i++)
{
send(bytes);
}

/* receiver */
float theValue;
unsigned char bytes[sizeof theValue];
int i;
for (i = 0; i < sizeof theValue; i++)
{
receive(&bytes);
}
theValue = *((float *) bytes);

Quick, dirty, and unsafe, but it should give you a place to start. The
above code basically treats theValue as an array of unsigned char. You
will probably want to develop a more robust protocol for both ends that
takes different endianess and representation in account.

Note that I know less than nothing about serial comms, so this may not
be what you want.
 
S

Simon Biber

John said:
The following assumes that both ends of the communication line are the
same byte sex and use the same representation for float:

/* sender */
float theValue;
unsigned char *bytes = (unsigned char *)&theValue;
int i;

This variable should be of type size_t.
for (i = 0; i < sizeof theValue; i++)
{
send(bytes);
}
>
/* receiver */
float theValue;
unsigned char bytes[sizeof theValue];
int i;


Again, size_t.
for (i = 0; i < sizeof theValue; i++)
{
receive(&bytes);
}
theValue = *((float *) bytes);


The bytes array is not necessarily aligned correctly to read a float
value out of it. You should either store the bytes directly into
theValue as you read them, or use memcpy to copy them across.
 
M

Martin Ambuhl

Kosio said:
-Hello,

I'm looking for a way to deconstruct a (32 bit) float value to four
(8 bit) char values. I then need a way to take those four (8 bit) char
values and construct a (32 bit) float value.

Does this help?
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <float.h>

int main(void)
{
float x, y;
unsigned char c[sizeof(float)];
size_t i, j;

srand(time(0));
for (i = 0; i < 3; i++) { /* three examples */
/* get a float to play with */
x = 101. * rand() / (1. + RAND_MAX) - 50.;
printf("original float: %.*g\n", FLT_DIG, x);
/* deconstruct it */
memcpy(c, &x, sizeof(float));
printf("decomposed into: ");
for (j = 0; j < sizeof(float); j++)
printf(" %#02x", c[j]);

/* put it back together */
memcpy(&y, c, sizeof(float));
printf("\nreconstituted as %.*g\n\n", FLT_DIG, y);
}
return 0;
}

original float: 0.259385
decomposed into: 0x1a 0xce 0x84 0x3e
reconstituted as 0.259385

original float: -22.167
decomposed into: 0x18 0x56 0xb1 0xc1
reconstituted as -22.167

original float: 11.621
decomposed into: 0x9b 0xef 0x39 0x41
reconstituted as 11.621
 
E

Emmanuel Delahaye

Kosio wrote on 16/09/05 :
I'm looking for a way to deconstruct a (32 bit) float value to four
(8 bit) char values. I then need a way to take those four (8 bit) char
values and construct a (32 bit) float value.

The reason I ask is that I am sending things across an rs485 serial
network, and the protocol is set up to send byte by byte. It sends one
(8 bit) char at a time. I would like to send a float across this
network in the form of four chars...

Are sure that the internal format of the floating points ont the source
target is the same than the one on the destination target ?
Any ideas, suggestions? (Btw: this is a C compiler for a cypress
microcontroller, not a C++ compiler)

You could use a simple loop with a & mask (0xFF) and a shift to right
(>>) to extract the bits eight by eight and put them into the UART send
register.

It would break a network rule (MSB-first), but is it important here ?

If you want portability, the best is to transmit a character-based
format (sprintf() is your friend). Portable binary formats do exist,
but they are complicated.


--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"Mal nommer les choses c'est ajouter du malheur au
monde." -- Albert Camus.
 
E

Emmanuel Delahaye

Martin Ambuhl wrote on 16/09/05 :
Kosio said:
-Hello,

I'm looking for a way to deconstruct a (32 bit) float value to four
(8 bit) char values. I then need a way to take those four (8 bit) char
values and construct a (32 bit) float value.

Does this help?
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <float.h>

int main(void)
{
float x, y;
unsigned char c[sizeof(float)];
size_t i, j;

srand(time(0));
for (i = 0; i < 3; i++) { /* three examples */
/* get a float to play with */
x = 101. * rand() / (1. + RAND_MAX) - 50.;
printf("original float: %.*g\n", FLT_DIG, x);
/* deconstruct it */
memcpy(c, &x, sizeof(float));
printf("decomposed into: ");
for (j = 0; j < sizeof(float); j++)
printf(" %#02x", c[j]);

/* put it back together */
memcpy(&y, c, sizeof(float));
printf("\nreconstituted as %.*g\n\n", FLT_DIG, y);
}
return 0;
}

original float: 0.259385
decomposed into: 0x1a 0xce 0x84 0x3e
reconstituted as 0.259385

original float: -22.167
decomposed into: 0x18 0x56 0xb1 0xc1
reconstituted as -22.167

original float: 11.621
decomposed into: 0x9b 0xef 0x39 0x41
reconstituted as 11.621

The problem is that the user wants a decomposition in 8-bit patterns.
Your code workd with CHAR_BIT = 8, bit is not portable.

/********************************************************************/
/* LIMITS.H v3.10 */
/* Copyright (c) 1993-1998 Texas Instruments Incorporated */
/********************************************************************/
#ifndef _LIMITS
#define _LIMITS

#define CHAR_BIT 16 /* NUMBER OF BITS IN TYPE CHAR
*/
#define SCHAR_MAX 32767 /* MAX VALUE FOR SIGNED CHAR
*/
#define SCHAR_MIN (-SCHAR_MAX-1) /* MIN VALUE FOR SIGNED CHAR
*/
#define UCHAR_MAX 65535u /* MAX VALUE FOR UNSIGNED CHAR
*/
#define CHAR_MIN SCHAR_MIN /* MIN VALUE FOR CHAR
*/
#define CHAR_MAX SCHAR_MAX /* MAX VALUE FOR CHAR
*/
#define MB_LEN_MAX 1

#define SHRT_MAX 32767 /* MAX VALUE FOR SHORT
*/
#define SHRT_MIN (-SHRT_MAX-1) /* MIN VALUE FOR SHORT
*/
#define USHRT_MAX 65535u /* MAX VALUE FOR UNSIGNED SHORT
*/

#define INT_MAX 32767 /* MAX VALUE FOR INT
*/
#define INT_MIN (-INT_MAX-1) /* MIN VALUE FOR INT
*/
#define UINT_MAX 65535u /* MAX VALUE FOR UNSIGNED INT
*/

#define LONG_MAX 2147483647 /* MAX VALUE FOR LONG
*/
#define LONG_MIN (-LONG_MAX-1) /* MIN VALUE FOR LONG
*/
#define ULONG_MAX 4294967295 /* MAX VALUE FOR UNSIGNED LONG
*/

#endif

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"Clearly your code does not meet the original spec."
"You are sentenced to 30 lashes with a wet noodle."
-- Jerry Coffin in a.l.c.c++
 
B

Baxter

I'd use a union.

union {
float fPart;
char cPart[sizeof(float)];
} uVal;


uVal.fPart = fTheFloatIwantToSend;

for (int i=0; i<sizeof(uVal); ++i) {
// send uVal.cPart;
}

On the receiving end, just reverse the process.
 
P

Peter Nilsson

[Please don't top-post.]
I'd use a union.

You don't need a union.

float f;
unsigned char *p = (unsigned char *) &f;
union {
float fPart;
char cPart[sizeof(float)];

unsigned char is better as plain char may not represent the full
range of a byte.
} uVal;


uVal.fPart = fTheFloatIwantToSend;

for (int i=0; i<sizeof(uVal); ++i) {

The size of the union may be larger than the size of the float.
// send uVal.cPart;
}

On the receiving end, just reverse the process.
 
B

Baxter

Peter Nilsson said:
[Please don't top-post.]

Please don't be a NetNanny.
You don't need a union.

I didn't say you did.
float f;
unsigned char *p = (unsigned char *) &f;
union {
float fPart;
char cPart[sizeof(float)];

unsigned char is better as plain char may not represent the full
range of a byte.

Depends on how your system and/or compiler defines a char. Some of the
compilers I use default to treating all "char" as "unsigned char". And most
allow that setting. If you really want to pick nits, then use byte (if
available) instead of char (or unsigned char).
The size of the union may be larger than the size of the float.

Shouldn't be - but if you're talking about possible padding, there's several
solutions:
- #pragma pack(1)
- for (int i=0; i<sizeof(float); ++i) {
- for (int i=0; i<sizeof(uVal.cPart); ++i) {

// send uVal.cPart;
}

On the receiving end, just reverse the process.



Getting used to unions makes it easier if you ever need to work with endian
problems.
 
K

Keith Thompson

Baxter said:
Peter Nilsson said:
[Please don't top-post.]

Please don't be a NetNanny.

Articles are easiest to read if each individual article can be read by
itself from top to bottom. Top-posting makes that more difficult,
especially in an environment like this one where most people *don't*
top-post. Peter asked you as politely as he possibly could not to do
that. I hardly think an insult was the appropriate response.

[snip]
Depends on how your system and/or compiler defines a char.

Yes, that's precisely the point.
Some of the
compilers I use default to treating all "char" as "unsigned char".

And some don't. If you char about signedness, you should specify it.
And most
allow that setting.

Perhaps, but writing code that depends on such a setting, when it's
trivial to wrote portable code that works *regardless* of any such
setting, is a bad idea.
If you really want to pick nits, then use byte (if
available) instead of char (or unsigned char).

There is no predefined type "byte" in C.

The solution is mind-bogglingly simple: use unsigned char.

[...]
Shouldn't be - but if you're talking about possible padding, there's several
solutions:
- #pragma pack(1)

That's non-standard.

[snip]
 
D

Default User

Baxter said:
Peter Nilsson said:
[Please don't top-post.]

Please don't be a NetNanny.


Top-posting is not favored in this newsgroup. If you want to be a
participant (that means not plonked or ignored by most of the
experienced contributors) you will refrain from doing so.



Brian
 
B

Baxter

Keith Thompson said:
Baxter said:
Peter Nilsson said:
[Please don't top-post.]

Please don't be a NetNanny.

Articles are easiest to read if each individual article can be read by
itself from top to bottom.

Baloney. amUsenet servers store the old posts for reference. Modern
usenet clients thread the conversation. Each post does NOT have to stand
alone. Viewers do not need to scroll through pages of previous dreck to get
to your one sentence at the bottom, nor do they need to re-read the entire
conversation each time.
Top-posting makes that more difficult,
especially in an environment like this one where most people *don't*
top-post. Peter asked you as politely as he possibly could not to do
that. I hardly think an insult was the appropriate response.

Bottom posting is a -religion-.
That's non-standard.
Maybe you need new compiler. I'm using at least six different compilers
(for three different environments) and every one of them has that option.

Enough of the flame war - I'd like to address an issue: "The size of the
union may be larger than the size of the float."

After I posted, I recalled that unions used to be used to minimize storage,
and could contain elements of unequal size. For the most part (the
exception being Embedded programming), that usage is obsolete. In this
case, we were using a union specifically to look at storage two different
ways.
 
B

Baxter

If you thing someone who's written over a million lines of C/C++ code and
has many, many commercial programs to his credit is not worth listening to,
then be my guest.

Do note, however, that of all the responses on this question, mine was the
only one to even bring up the subject of unions.

--
---------------------------------------------------------------------
DataGet & PocketLog www.dataget.com
Data Collectors www.baxcode.com
--------------------------------------------------------------------



Default User said:
Baxter said:
Peter Nilsson said:
[Please don't top-post.]

Please don't be a NetNanny.


Top-posting is not favored in this newsgroup. If you want to be a
participant (that means not plonked or ignored by most of the
experienced contributors) you will refrain from doing so.



Brian
 
W

Walter Roberson

Baloney. amUsenet servers store the old posts for reference.

Article retention times vary greatly, and are not always predictable.
It is common for the server I use to expire large sets of articles when
it runs low on space, rather than retaining them for any set period of
time. Sometimes retention on this particular server is only about 3 1/2
days, which is not long enough to encompass most discussion threads.

Modern usenet clients thread the conversation.

Who said people are using "modern" usenet clients? My client binary
is probably at least a decade old.

And threading doesn't help if the previous message has expired or has
not arrived. (Non-propogation is a noticable problem between the
two competing major ISPs hereabouts.)
Each post does NOT have to stand
alone. Viewers do not need to scroll through pages of previous dreck to get
to your one sentence at the bottom, nor do they need to re-read the entire
conversation each time.

How many hundreds of postings do you read per day? How many postings
can you remember simultaneously? Remember well enough to differentiate
between two posters with the same question but whose circumstances
are a hair different, thus requiring completely different answers ?

Not quoting might work for people who come in, look at a very small
number of postings and get out again, but failure to quote appropriately
is rough on the regulars who contribute by far the majority of the answers.
 
F

Flash Gordon

Baxter said:
Baxter said:
[Please don't top-post.]

Please don't be a NetNanny.

Articles are easiest to read if each individual article can be read by
itself from top to bottom.

Baloney. amUsenet servers store the old posts for reference. Modern
usenet clients thread the conversation. Each post does NOT have to stand
alone.

Apart from when the news server has not even *received* the message (I
know not all messages reach all servers) or people who have there
clients configured not to show old posts so that the can immediately see
the new posts rather than screen fulls of listings of old posts, or
people who are just joining the group and the message you are replying
to has just fallen off the retention, or...
> Viewers do not need to scroll through pages of previous dreck to get
to your one sentence at the bottom, nor do they need to re-read the entire
conversation each time.

That is why one snips the parts one is not replying to.
Bottom posting is a -religion-.

No, it is a long standing convention.
Maybe you need new compiler.

Changing compiler won't make it standard, only the standards body can do
that and they have not.
> I'm using at least six different compilers
(for three different environments) and every one of them has that option.

So your experience is limited. Even on systems where there is a pack
pragma or something similar it could easily have a significant impact on
performance.
Enough of the flame war - I'd like to address an issue: "The size of the
union may be larger than the size of the float."

After I posted, I recalled that unions used to be used to minimize storage,
and could contain elements of unequal size. For the most part (the
exception being Embedded programming), that usage is obsolete.

I just had a look in the source code for the latest versions (this
years) of some SW and found a few unions being used. This is *not*
embedded SW, so not everyone agrees with you that it is mostly obsolete
outside embedded programming.

If I have a mutually exclusive set of fields then I would certainly
consider using a union since it makes it clear to anyone reading the
definition that they *are* mutually exclusive.
> In this
case, we were using a union specifically to look at storage two different
ways.

Which is where the issue of pacing arrives.
 
F

Flash Gordon

Baxter said:
If you thing someone who's written over a million lines of C/C++ code and
has many, many commercial programs to his credit is not worth listening to,
then be my guest.

There are billions of lines of bad code and loads of commercial programs
that are completely rubbish, so saying that means nothing.
Do note, however, that of all the responses on this question, mine was the
only one to even bring up the subject of unions.

Yes, and you failed to allow for a problem in that solution and when it
was pointed out suggested a non-standard pragma as a work around, and
when that was pointed out suggested that if it was not available people
should upgrade their compilers. Not a set of posts that inspires my
confidence in your skills.
 
D

Default User

Baxter said:
If you thing someone who's written over a million lines of C/C++
code and has many, many commercial programs to his credit is not
worth listening to, then be my guest.


I do think that someone who refuses to post in an intelligent manner is
not worth listening to, yes. Understand that to top-posting question is
not a matter of taste, but of clear communications.

So, yes, it's *plonk* for you.



Brian
 
W

Walter Roberson

Do note, however, that of all the responses on this question, mine was the
only one to even bring up the subject of unions.

This isn't comp.programming in which any trick that comes along may be
used. This is comp.lang.c, which concerns itself with well-defined
(and hence portable) C programming.

Thus, your suggestion to use #pragma pack would have been fine for
discussions in a newsgroup for a specific implementation, but here in
c.l.c., the answer would be that if you need some particular behaviour
out of a #pragma then you are working non-portably.

The C89 description of #pragma says merely that it leads to
implementation specific behaviour. It would, for example, be perfectly
conforming as far as C89 is concerned if upon encountering #pragma pack
that the compiler decided that it needed to handle *all* memory loads
byte-by-byte -- just in case the data happened to be unaligned.

Do note, however, that of all the responses on this question, mine was the
only one to even bring up the subject of unions.

That's because your use of unions was not portable. You wrote,
union {
float fPart;
char cPart[sizeof(float)];
} uVal;

See however, C89 3.3.2.3 Structure and Union Members:

With one exception, if a member of a union object is accessed after a
value has beeen stored in a different member of the object, the behaviour
is implementation-defined. One special guarantee is made in order to
simplify the use of unions: If a union contains several structures
that share a common initial sequence (see below), and if the union
object currently contains one of those structures, it is permitted to
inspect the common initial part of any of them. Two structures share
a common initial sequence if corresponding members have compatible
types (and, for bit-fields, the same widths) for a sequence of one
or more initial members.

uVal.fPart = fTheFloatIwantToSend;
for (int i=0; i<sizeof(uVal); ++i) {
// send uVal.cPart;
}



The footnote to the above paragraph specifically indicates that
the byte order is not guaranteed when inspecting the other member as char[].

We can presume from the original poster's question that the float
representation is compatible between the transmitter and receiver,
but we should not presume that the byte order within the float is
compatible.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,733
Messages
2,569,440
Members
44,832
Latest member
GlennSmall

Latest Threads

Top