Floats to chars and chars to floats

K

Keith Thompson

Baxter said:
Keith Thompson 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. 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.

With all due respect, you are simply wrong.

The solution to the "pages of previous dreck" problem is to trim any
quoted material to what is actually relevant to your followup. It
takes a little time and thought, but it will save your readers far
more time than it costs you.

Browse this newsgroup to see how it's done.
Bottom posting is a -religion-.

No, bottom posting is a convention that has served us very well here
in the comp.lang.c community for many years. There are good reasons
for it, which have been explained repeatedly and at length. Now you
come in here and tell us we've been doing it wrong all this time.
Give us a little credit; we know what we're doing and why.
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.

Perhaps so. Does the compiler I'm using have that option? What about
the compiler the original poster is using? You don't know, and
neither do I.

I just tried a small test case on several compilers that I use; on
three of them, "#pragma pack(1)" appears to be ignored (which is what
the standard specifies for unrecognized pragmas). Are you sure it
actually *works* on all six of your compilers?

This is why we generally limit discussion here to standard C.
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.

I'll leave any technical discussions for others, at least for now.
 
W

Walter Roberson

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

The original poster's requirements are that the data be transmitted
8-bits at a time. Your code does not portably do that.

Suppose one is using an architecture in which sizeof(float) is 1 --
that is, that a float and a char occupy the same amount of storage.
sizeof does not deal in units of 8-bit bytes: it deals in multiples
of the size occupied by a char in the implementation (which might
or might not be the same as the size of the minimum individually-
addressible element at the machine level.)

Due to the minimum precisions required of float, sizeof(float) == 1
would imply that CHAR_BITS was at least 32.

Your union type-punning (which invokes implementation-defined behaviour,
as I indicated earlier) would then end up as char cPart[1]
and cPart would grab the whole float... in an unspecified internal
bit order. The task of breaking that 32 (or more) bit char into
8 bit chunks would not have been accomplished by your code.
 
B

Baxter

Using a union for *mutual exclusivity* would be counter-productive - since a
union, by definition, looks at the same space. A union simply lets you look
at the same space (and the contents thereof) in different ways.
 
B

Baxter

That's why I mentioned "byte" - where "byte" is defined, either by the
system or by the programmer to be 8-bit.

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


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

The original poster's requirements are that the data be transmitted
8-bits at a time. Your code does not portably do that.
 
W

Walter Roberson

Peter Nilsson said:
Baxter wrote:
union {
float fPart;
char cPart[sizeof(float)];
} uVal;
for (int i=0; i<sizeof(uVal); ++i) {
The size of the union may be larger than the size of the float.

Could you expand on that, Peter?

Padding is allowed on the end {only} of unions, if necessary in order
to fill out the union in case it is used within an array or struct.

You {usually} don't need padding to put two floats side by side.

By definition, sizeof(float) is the number of char-width-
equivilents that is needed to store a float.

Therefore, char[sizeof(float)] is going to be the same size as a float,
-unless- somehow you need padding after the end of a char in order
to do proper address alignment of char's.

I'm trying to think of circumstances under which that would be possible,
that an array of char might require internal padding. It seems somewhat
unlikely, verging on the "Surely that's not allowed by the Standard ??"


Someone... is there a DS9000 in which (say) a float occupies
4 bytes, a char occupies 1 byte, but the address alignment restriction
for char is 2 bytes?

[float byte 0][float byte 1 ][float byte 2][float byte 3]
[char [0] ][unaddressible][char [1] ][unaddressible]


Hmmm, I guess it is also possible that the alignment requirement
for float could be 8 but the size of float could be 4, which -would-,
I guess, lead to padding at the end of the union.
 
M

Mark McIntyre

Baloney. amUsenet servers store the old posts for reference.

So fscking what? You expect me to waste my bandwidth hunting for old
articles, or trying to understand what on earth you're responding to
in a thread with a dozen contributors? And what about when your server
purges posts older than say a day?
Modern usenet clients thread the conversation.

So what? Modern usenet servers have purge times measured in hours in
some cases, and not everyone keeps every single post on their own PC.
Each post does NOT have to stand alone.

You've clearly never come back from holiday and tried to catch up.
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.

So what? Do you have a clue what non-standard means? Point out where
in the ISO C Standard it says that pragma pack() has to do anything.
 
W

Walter Roberson

The original poster's requirements are that the data be transmitted
8-bits at a time. Your code does not portably do that.
[/QUOTE]
That's why I mentioned "byte" - where "byte" is defined, either by the
system or by the programmer to be 8-bit.

There is nothing in C89 that allows one to define an 8-bit entity
at all portably.

In C99, there is a uint8_t but C99 defines it in such a way that
support for it is optional in an implementation. Your sample code
did not test for the appropriate macro that would indicate the
existance of uint8_t .

Thus, your code is not portable.
 
M

Mark McIntyre

Using a union for *mutual exclusivity* would be counter-productive - since a
union, by definition, looks at the same space. A union simply lets you look
at the same space (and the contents thereof) in different ways.

I beg to differ. I typically think of a union as allowing you to use
the same space to store different things.

Accessing the storage as different types is not guaranteed to work
since unused bits may contain unspecified values. It won't trap,
however. (6.2.6.1)
 
M

Mark McIntyre

If you thing someone who's written over a million lines of C/C++ code and
has many, many commercial programs to his credit

Some of the top posters here finished college only a couple of years
back. Some have pedigrees going back to the origins of C. So boasting
about your MLOC serves no purpose in CLC. Nobody gives a sh*t if
you've written one or a trillion lines.
is not worth listening to,then be my guest.

Its likely to be your fate, if you insist on top-posting/
Do note, however, that of all the responses on this question, mine was the
only one to even bring up the subject of unions.

I'm not sure why this is relevant to a discussion about your trampling
over the conventions of CLC. Being arrogant just gets you killfiled
faster.
 
M

Martin Ambuhl

Baxter said:
Using a union for *mutual exclusivity* would be counter-productive - since a
union, by definition, looks at the same space. A union simply lets you look
at the same space (and the contents thereof) in different ways.

Baxter has previously written in 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.

We have here a case in point of how little one can believe claims of
expertise by posters. His suggestion of what unions are for is in fact
an extremely poor idea since, as the standard says
With one exception, if the value of a member of a union
object is used when the most recent store to the object was
to a different member, the behavior is
implementation-defined.

We now know to ve wary of the over a million lines of code he has
written in the mythical "C/C++" language. If he had any integrity, he
would name the "many, many commercial programs to his credit" so we can
avoid them.
 
M

Martin Ambuhl

Baxter said:
That's why I mentioned "byte" - where "byte" is defined, either by the
system or by the programmer to be 8-bit.

If you have actually written "millions of lines of C/C++ code" and have
"many, many commercial programs to [your] credit," then you should know
the difference between the words "octet" and "byte." If so, you would
know better than to use the word "byte" in this context. Otherwise, you
are nothing but an ignorant poseur.
 
K

Keith Thompson

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

The original poster's requirements are that the data be transmitted
8-bits at a time. Your code does not portably do that.

That's why I mentioned "byte" - where "byte" is defined, either by the
system or by the programmer to be 8-bit.

I've corrected your top-posting. Please stop doing that. We've asked
politely, and we've explained why we're asking. I can understand the
temptation to be deliberately obnoxious sometimes, but it's getting
old.

Perhaps you weren't aware that the term "byte" has a definition in the
C standard -- and it doesn't mean "8 bits". A "byte" is an
"addressable unit of data storage large enough to hold any member of
the basic character set of the execution environment". It is required
to be at least 8 bits (CHAR_BIT >= 8), but it can be bigger -- and
there are real systems on which it is.

Even outside the context of C, the term "byte" has not always meant 8
bits; some might argue that it never has. Systems with 6-bit or 9-bit
bytes used to be common, though they're less so today.

If you want to discuss 8-bit quantities in this newsgroup, I suggest
using the term "octet".

Having said that, most or all current hosted (non-embedded) C
implementations use 8-bit bytes, and depending on the application you
might legitimately not care about portability to systems with larger
bytes. If that's the case, you might consider adding something like
this to the top of your program:

#include <limits.h>
#if CHAR_BIT != 8
#error "This code assumes 8-bit bytes."
#endif
 
O

ozbear

Peter Nilsson said:
Baxter wrote:
union {
float fPart;
char cPart[sizeof(float)];
} uVal;
for (int i=0; i<sizeof(uVal); ++i) {
The size of the union may be larger than the size of the float.

Could you expand on that, Peter?

Padding is allowed on the end {only} of unions, if necessary in order
to fill out the union in case it is used within an array or struct.

You {usually} don't need padding to put two floats side by side.

By definition, sizeof(float) is the number of char-width-
equivilents that is needed to store a float.

Therefore, char[sizeof(float)] is going to be the same size as a float,
-unless- somehow you need padding after the end of a char in order
to do proper address alignment of char's.

I'm trying to think of circumstances under which that would be possible,
that an array of char might require internal padding. It seems somewhat
unlikely, verging on the "Surely that's not allowed by the Standard ??"
<snip>

How about the DS9000 case where a char occupies 10 bits but a float
occupies 32. sizeof(float) = 4, minimally, since 3*10 isn't
enough. The resulting union must have therefore have minimally 40
bits in it which is longer than the original float.

Oz
 
T

Tim Rentsch

Therefore, char[sizeof(float)] is going to be the same size as a float,
-unless- somehow you need padding after the end of a char in order
to do proper address alignment of char's.

I'm trying to think of circumstances under which that would be possible,
that an array of char might require internal padding. It seems somewhat
unlikely, verging on the "Surely that's not allowed by the Standard ??"

It can't happen. I asked about the possibility of array
padding in comp.std.c not too long ago. If T is a type,
sizeof(T[N]) == N * sizeof(T). No padding.

(Of course, I mean T to be such that the type T[N] is an
array type with elements of type T.)

Someone... is there a DS9000 in which (say) a float occupies
4 bytes, a char occupies 1 byte, but the address alignment restriction
for char is 2 bytes?

[float byte 0][float byte 1 ][float byte 2][float byte 3]
[char [0] ][unaddressible][char [1] ][unaddressible]


Hmmm, I guess it is also possible that the alignment requirement
for float could be 8 but the size of float could be 4, which -would-,
I guess, lead to padding at the end of the union.

The alignment requirement for any type T can't be more than
sizeof(T). More specifically, alignment_of(T) must evenly
divide sizeof(T). This result follows from the relationship
above about array sizes.
 
K

Keith Thompson

How about the DS9000 case where a char occupies 10 bits but a float
occupies 32. sizeof(float) = 4, minimally, since 3*10 isn't
enough. The resulting union must have therefore have minimally 40
bits in it which is longer than the original float.

Not possible. Type float, like any non-bitfield type, must occupy a
whole number of bytes. If CHAR_BIT==10 and sizeof(float)==4, a float
occupies 40 bits. Some of them might be padding bits (though strictly
speaking the standard only defines the term "padding bits" for integer
types), but all 40 bits are part of the float object.
 
P

Peter Nilsson

Walter said:
Peter Nilsson said:
Baxter said:
union {
float fPart;
char cPart[sizeof(float)];
} uVal;
for (int i=0; i<sizeof(uVal); ++i) {
The size of the union may be larger than the size of the float.

Could you expand on that, Peter?

Padding is allowed on the end {only} of unions, if necessary in order
to fill out the union in case it is used within an array or struct.

No, padding can be put in for any reason, though it must preserve
alignment.
You {usually} don't need padding to put two floats side by side.

By definition, sizeof(float) is the number of char-width-
equivilents that is needed to store a float.

Therefore, char[sizeof(float)] is going to be the same size as a float,
-unless- somehow you need padding after the end of a char in order
to do proper address alignment of char's.

Yes, but sizeof(uVal) needn't be sizeof(uVal.cpart).
I'm trying to think of circumstances under which that would be possible,
that an array of char might require internal padding. It seems somewhat
unlikely, verging on the "Surely that's not allowed by the Standard ??"

It is unlikely, but realise that (implicitly in C90) all union pointers
have the same size and representation. Hence an implementation with
different pointer types[1][2] may choose to pad unions to make the
choice of (internal) pointer type easier (and/or efficient.)[3]

[1] There are plenty of systems where character pointers are subtly
different to other pointers. [e.g. past Crays.] Chris Torek has even
given an example of an old system where void * pointers and int *
pointers had different sizes.

[2] On such machines, conversions of pointers may not be no-ops.

[3] And when was the last time you saw a union that only had character
members, or character agregate members? If dealing with non character
types is simpler through a specific pointer class, then it makes sense
to chose that type for unions/structs.
 
W

Walter Roberson

Walter Roberson wrote:
No, padding can be put in for any reason, though it must preserve
alignment.

The wording in C89 about unions indicates that padding is allowed
only at the end of the union: each member of the union is
required to start at the common address. That's a bit different
than "padding can be put in for any reason", which statement
could be interpreted as indicating that padding could occur
at the beginning.
 
W

Walter Roberson

Walter Roberson wrote:
It is unlikely, but realise that (implicitly in C90) all union pointers
have the same size and representation. Hence an implementation with
different pointer types[1][2] may choose to pad unions to make the
choice of (internal) pointer type easier (and/or efficient.)[3]

Hmmm, that doesn't feel right to me. It looks to me that you are
conflating alignment and padding. Any particular union type only needs
as much alignment as the most restrictive member, so a pointer to a
union A need not have the same size or representation as a pointer to a
different kind of union B.

For example, for union { short u1s; int u1i; } the pointer that could
be used could be an int pointer: you cannot portably allocate
this union on a short or char boundary that is not an int boundary.
If short* has a different representation in the architecture, then
the code would contain an int* to short* pointer conversion only
at those places where the short was being accessed.

For union { short u2s; } without the int member, a short* would have
to be used instead of the int* of the first union.

Thus, the pointer type would have to be consistant for any one
union variety, but would not have to be consistant for -all- unions.
 
T

Tim Rentsch

Walter Roberson wrote:
It is unlikely, but realise that (implicitly in C90) all union pointers
have the same size and representation. Hence an implementation with
different pointer types[1][2] may choose to pad unions to make the
choice of (internal) pointer type easier (and/or efficient.)[3]

Hmmm, that doesn't feel right to me. It looks to me that you are
conflating alignment and padding. Any particular union type only needs
as much alignment as the most restrictive member, so a pointer to a
union A need not have the same size or representation as a pointer to a
different kind of union B.

Actually, it does. 6.2.5 p26: "All pointers to union types
shall have the same representation and alignment requirements as
each other."
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top