[comp.lang.c] Type punning in C

desj@idacrd.UUCP (David desJardins) (10/02/89)

   Does anyone have any ideas on how one should go about converting an
integer to the floating-point number with the same bit pattern?  One
frequently (well, occasionally) needs to do this to implement certain
bit manipulations efficiently on Cray computers and other vector
machines, and possibly on other architectures with fast floating-point
but no fast shift (?).  The best way I have found to do this in
FORTRAN is to write

      INTEGER I
      REAL X
      X = OR (I, 0).

(The Cray FORTRAN compiler optimizes out the trivial OR instruction.)

   It doesn't seem that there is any equally straightforward way to
accomplish this in C.  I don't want to involve pointers because the
whole point is efficiency, and I expect that it will be very difficult
for any compiler to optimize out the dereferences in something like

      int i;
      float x;
      * (int *) & x = i;

to produce a single register-to-register transfer (or not even that).

   What I think is probably necessary is to define a real function of
one integer argument, returning the same bit pattern as its input.
Ultimately I would need to get Cray to incorporate it into their C
compiler as an intrinsic function.  Does anyone have any experience
with such a thing, or a good idea of how these functions should be
named?

   -- David desJardins

gwyn@smoke.BRL.MIL (Doug Gwyn) (10/07/89)

In article <475@idacrd.UUCP> desj@idacrd.UUCP (David desJardins) writes:
>   Does anyone have any ideas on how one should go about converting an
>integer to the floating-point number with the same bit pattern?

The simple answer is, you shouldn't need to do that!

However, C does provide "union" types that can be used for such purposes.
Load the bit pattern into the integer union member and extract it via the
floating-point member.

henry@utzoo.uucp (Henry Spencer) (10/08/89)

In article <475@idacrd.UUCP> desj@idacrd.UUCP (David desJardins) writes:
>   Does anyone have any ideas on how one should go about converting an
>integer to the floating-point number with the same bit pattern?  ...
>   It doesn't seem that there is any equally straightforward way to
>accomplish this in C.  I don't want to involve pointers ...

You might try unions.  This is one of the things they're good for,
albeit in a very implementation-specific way.  (Not a problem here,
since the operation is inherently implementation-specific.)

If your compiler won't put unions into registers, complain to your supplier.  
-- 
A bit of tolerance is worth a  |     Henry Spencer at U of Toronto Zoology
megabyte of flaming.           | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

ok@cs.mu.oz.au (Richard O'Keefe) (10/08/89)

In article <475@idacrd.UUCP>, desj@idacrd.UUCP (David desJardins) writes:
>    Does anyone have any ideas on how one should go about converting an
> integer to the floating-point number with the same bit pattern?

	union { long i; float x; } pun;
	pun.i = the_integer_to_be_converted;
	the_single_precision_result = pun.f;

> One frequently (well, occasionally) needs to do this to implement certain
> bit manipulations efficiently on Cray computers and other vector machines ...

Just which operations are these?  If the operations are meaningful functions
of floating-point numbers (e.g. things like ilogb() copysign() nextafter())
it might make more sense to ask Cray to put _those_ in their library.

I really would like to know what the operations are.

tanner@cdis-1.uucp (Dr. T. Andrews) (10/09/89)

henry@utzoo.uucp (Henry Spencer) writes:
) If your compiler won't put unions into registers, complain to
) your supplier.  
Done, long ago.  Our internal reference shows it as our item
"pfc155.c" of 15-Jan-87, vendor's reference number 0380101.

The vendor's comment?  He said that they don't have to put unions
in registers because "register" is just a hint, and they're free to
do whatever they want to.
-- 
Cutting half of passenger service | {bpa,uunet}!cdin-1!cdis-1!tanner
Mulroney: "cold froze our brains" | {attctc gatech!uflorida}!ki4pv!cdis-1!tanner

bright@Data-IO.COM (Walter Bright) (10/10/89)

In article <475@idacrd.UUCP> desj@idacrd.UUCP (David desJardins) writes:
<   Does anyone have any ideas on how one should go about converting an
<integer to the floating-point number with the same bit pattern?

Try a union:
	union blah { int i; float f; } x;
	x.f = f;
	/* now manipulate x.i */

<   It doesn't seem that there is any equally straightforward way to
<accomplish this in C.  I don't want to involve pointers because the
<whole point is efficiency, and I expect that it will be very difficult
<for any compiler to optimize out the dereferences in something like
<      int i;
<      float x;
<      * (int *) & x = i;
<to produce a single register-to-register transfer (or not even that).

Not at all. It's a pretty much standard and trivial optimization to
convert *(int*)&x=i into MOV X,I. Feel free to use it, with the caveat
that float format is not the same from machine to machine. I've done
it many times to do special manipulations on doubles.

cik@l.cc.purdue.edu (Herman Rubin) (10/10/89)

In article <2165@dataio.Data-IO.COM>, bright@Data-IO.COM (Walter Bright) writes:
> In article <475@idacrd.UUCP> desj@idacrd.UUCP (David desJardins) writes:
| <   Does anyone have any ideas on how one should go about converting an
| <integer to the floating-point number with the same bit pattern?
> 
> Try a union:
> 	union blah { int i; float f; } x;
> 	x.f = f;
> 	/* now manipulate x.i */

			.......................

| <      int i;
| <      float x;
| <      * (int *) & x = i;
| <to produce a single register-to-register transfer (or not even that).
> 
> Not at all. It's a pretty much standard and trivial optimization to
> convert *(int*)&x=i into MOV X,I. Feel free to use it, with the caveat
> that float format is not the same from machine to machine. I've done
> it many times to do special manipulations on doubles.

This may or may not work.  It is likely that the "&" by itself will force
x to memory.  But event if a #define is used to eliminate that, al least on
may compilers the MOV X,I or equivalent will not work.  Reluctantly, I would
have to say that it might be necessary to put in a kludge and then edit the
.s files, which is what I find myself forced to do in these situations.
-- 
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907
Phone: (317)494-6054
hrubin@l.cc.purdue.edu (Internet, bitnet, UUCP)

lhf@aries5.uucp (Luiz H de Figueiredo) (10/10/89)

In article <11242@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:
>
>However, C does provide "union" types that can be used for such purposes.
>Load the bit pattern into the integer union member and extract it via the
>floating-point member.

Provided both members have the same size!
Otherwise, try

union
{
 float f;
 unsigned char b[sizeof(float)];
};

-------------------------------------------------------------------------------
Luiz Henrique de Figueiredo		internet: lhf@aries5.uwaterloo.ca
Computer Systems Group			bitnet:   lhf@watcsg.bitnet
University of Waterloo
-------------------------------------------------------------------------------
eof

jerry@violet.berkeley.edu ( Jerry Berkman ) (10/11/89)

In article <475@idacrd.UUCP> desj@idacrd.UUCP (David desJardins) writes:
>   Does anyone have any ideas on how one should go about converting an
>integer to the floating-point number with the same bit pattern?
>The best way I have found to do this in FORTRAN is to write

>      INTEGER I
>      REAL X
>      X = OR (I, 0).

>(The Cray FORTRAN compiler optimizes out the trivial OR instruction.)
>   -- David desJardins

Why not use equivalence?
	INTEGER I
	REAL X, IX
	EQUIVALENCE (X,IX)

	IX = I
The Fortran standard specifies that a REAL and INTEGER occupy the same space.
The only problem is this might fool some optimizers.

	- Jerry Berkman
	  jerry@violet.berkeley.edu

slimer@trsvax.UUCP (10/11/89)

In article <475@idacrd.UUCP>, desj@idacrd.UUCP (David desJardins) writes:
>	the_single_precision_result = pun.f;

  According to the pun union structure, this should actually read:

  the_single_precision_result = pun.x;


****************************************************************************
*  Thank You,                                  texbell!letni!rwsys!slimer  *
*         Bill             "Ever felt like a dip switch?" - ComputerWorld  *
*  George W. Pogue, 1300 Two Tandy, Fort Worth, TX. 76102  (817) 390-2871  *
****************************************************************************

diamond@csl.sony.co.jp (Norman Diamond) (10/11/89)

In article <475@idacrd.UUCP> desj@idacrd.UUCP (David desJardins) writes:

>   Does anyone have any ideas on how one should go about converting an
>integer to the floating-point number with the same bit pattern?
>The best way I have found to do this in FORTRAN is to write
>      INTEGER I
>      REAL X
>      X = OR (I, 0).
>(The Cray FORTRAN compiler optimizes out the trivial OR instruction.)

Looks like the Cray Fortran compiler has a bug.  The result of OR(I,0)
should be an integer, and the conversion from integer to floating
(across the assignment) should usually have a different bit pattern.

>I don't want to involve pointers
>      int i;
>      float x;
>      * (int *) & x = i;

This would look a little bit better as
       x = * (float *) & i;
although the effect is the same.

In fact with an optimizing compiler this should not be an efficiency
problem.  The problem comes about if you DECLARE register float x;
because it's illegal to apply the "&" operator to a register operand.
If your variables are auto but the optimizer is USING registers, it
will generally figure out register-to-register transfers.

On the other hand, how many hardware architectures have instructions
to transfer directly between integer registers and floating registers?
Usually you have to store it to RAM and load it back anyway.

Another solution is to use unions
       union {
	   int   i;
	   float x;
       } converter;
       converter.i = i;
       x = converter.x;
but most compilers will not put converter in a register for you.  This
time you could try it yourself, "register union ....." because you
aren't applying "&" to it, but I cannot imagine a compiler obeying your
"register" request.  Again, how many architectures put integers and
floats in the same register?

-- 
Norman Diamond, Sony Corp. (diamond%ws.sony.junet@uunet.uu.net seems to work)
  The above opinions are inherited by your machine's init process (pid 1),
  after being disowned and orphaned.  However, if you see this at Waterloo or
  Anterior, then their administrators must have approved of these opinions.
Newsgroups: comp.lang.c,comp.sys.super
Subject: Re: Type punning in C
Summary: 
Expires: 
References: <475@idacrd.UUCP>
Sender: 
Reply-To: diamond@riks. (Norman Diamond)
Followup-To: 
Distribution: 
Organization: Sony Computer Science Laboratory Inc., Tokyo, Japan
Keywords: 

In article <475@idacrd.UUCP> desj@idacrd.UUCP (David desJardins) writes:

>   Does anyone have any ideas on how one should go about converting an
>integer to the floating-point number with the same bit pattern?
>The best way I have found to do this in FORTRAN is to write
>      INTEGER I
>      REAL X
>      X = OR (I, 0).
>(The Cray FORTRAN compiler optimizes out the trivial OR instruction.)

Looks like the Cray Fortran compiler has a bug.  The result of OR(I,0)
should be an integer, and the conversion from integer to floating
(across the assignment) should usually have a different bit pattern.

>I don't want to involve pointers
>      int i;
>      float x;
>      * (int *) & x = i;

This would look a little bit better as
       x = * (float *) & i;
although the effect is the same.

In fact with an optimizing compiler this should not be an efficiency
problem.  The problem comes about if you DECLARE register float x;
because it's illegal to apply the "&" operator to a register operand.
If your variables are auto but the optimizer is USING registers, it
will generally figure out register-to-register transfers.

On the other hand, how many hardware architectures have instructions
to transfer directly between integer registers and floating registers?
Usually you have to store it to RAM and load it back anyway.

Another solution is to use unions
       union {
	   int   i;
	   float x;
       } converter;
       converter.i = i;
       x = converter.x;
but most compilers will not put converter in a register for you.  This
time you could try it yourself, "register union ....." because you
aren't applying "&" to it, but I cannot imagine a compiler obeying your
"register" request.  Again, how many architectures put integers and
floats in the same register?

-- 
Norman Diamond, Sony Corp. (diamond%ws.sony.junet@uunet.uu.net seems to work)
  The above opinions are inherited by your machine's init process (pid 1),
  after being disowned and orphaned.  However, if you see this at Waterloo or
  Anterior, then their administrators must have approved of these opinions.

ok@cs.mu.oz.au (Richard O'Keefe) (10/11/89)

In article <1989Oct10.185851.6490@agate.berkeley.edu>, jerry@violet.berkeley.edu ( Jerry Berkman ) writes:
: In article <475@idacrd.UUCP> desj@idacrd.UUCP (David desJardins) writes:
: >   Does anyone have any ideas on how one should go about converting an
: >integer to the floating-point number with the same bit pattern?

: Why not use equivalence?
: 	INTEGER I
: 	REAL X, IX
: 	EQUIVALENCE (X,IX)

Because he was asking how to do it in C.

I understand that the original problem was something that could be expressed	
quite clearly and simply as an ordinary C arithmetic expression operating
exclusively on integers, and that straightforward C code would _work_ on the
Cray, but because some operation (bitwise shifts?) didn't have a vector
equivalent it wouldn't vectorise.  But a hairy hack involving floats _would_
vectorise because the Cray system is good at vectorising float operations.

The interesting point here is that there are a lot of things you can do IF
you have the functions required and recommended in the IEEE 754 standard.
For example, if there is some reason why you want to avoid
	p << i		use	(int) scalb((float)p, i)
	p >> j		use	(int) scalb((float)p, -j)

This is why I think that it would be interesting for people with such
problems (and this includes Herman Rubin) to give us more detail about
the problem they are really trying to solve (e.g. the original poster's
problem was "how do I get results equal to these in a way that will
vectorise on a Cray?").  It may be that some of these problems have
solutions which are less machine-specific than hand-crafted bit-twiddling,
or would be if functional equivalents of the IEEE functions were provided.

exspes@gdr.bath.ac.uk (P E Smee) (10/11/89)

In article <1989Oct10.185851.6490@agate.berkeley.edu> jerry@violet.berkeley.edu ( Jerry Berkman ) writes:
>
>Why not use equivalence?
>	INTEGER I
>	REAL X, IX
>	EQUIVALENCE (X,IX)
>
>	IX = I
>The Fortran standard specifies that a REAL and INTEGER occupy the same space.
>The only problem is this might fool some optimizers.
>
Problem is, the Fortran standard *also* says that if your program tries
to take the value of the variable using a different type than the type you
used when you last stored into it, your program is invalid.  This is a
polite way of saying (to the user) 'this trick may not work', and (to the
compiler writer) 'your optimizer does not have to worry about aliasing
between variables of different types'.  If the compiler can tell that
you are going to (e.g.) store an integer into that storage, and then
read a real, it is under no obligation to make sure that the integer
value gets stored.

Fortran equivalence was designed toallow reuse of storage on the early
small memory machines -- not to allow type punning.  Usually you can
get away with punning, but it doesn't always work and so is a bad habit.

-- 
 Paul Smee               |    JANET: Smee@uk.ac.bristol
 Computer Centre         |   BITNET: Smee%uk.ac.bristol@ukacrl.bitnet
 University of Bristol   | Internet: Smee%uk.ac.bristol@nsfnet-relay.ac.uk
 (Phone: +44 272 303132) |     UUCP: ...!mcvax!ukc!gdr.bath.ac.uk!exspes

cik@l.cc.purdue.edu (Herman Rubin) (10/12/89)

In article <1989Oct11.091619.18336@gdt.bath.ac.uk>, exspes@gdr.bath.ac.uk (P E Smee) writes:
> In article <1989Oct10.185851.6490@agate.berkeley.edu> jerry@violet.berkeley.edu ( Jerry Berkman ) writes:
< >
< >Why not use equivalence?
< >	INTEGER I
< >	REAL X, IX
< >	EQUIVALENCE (X,IX)
< >
< >	IX = I
< >The Fortran standard specifies that a REAL and INTEGER occupy the same space.
< >The only problem is this might fool some optimizers.
< >
> Problem is, the Fortran standard *also* says that if your program tries
> to take the value of the variable using a different type than the type you
> used when you last stored into it, your program is invalid.  This is a
> polite way of saying (to the user) 'this trick may not work', and (to the
> compiler writer) 'your optimizer does not have to worry about aliasing
> between variables of different types'.  If the compiler can tell that
> you are going to (e.g.) store an integer into that storage, and then
> read a real, it is under no obligation to make sure that the integer
> value gets stored.
> 
> Fortran equivalence was designed toallow reuse of storage on the early
> small memory machines -- not to allow type punning.  Usually you can
> get away with punning, but it doesn't always work and so is a bad habit.

This is another example of those "gurus" who can not envision an intelligent
user using the machine in an intelligent manner, and prevent that use.  I
have deliberately used "type punning" on various machines, and I consider it
an extremely useful tool.  Now, I do not mind the compiler asking me if I
really wanted to do it, but I object to anyone telling me that I CAN NOT
use instructions that do what I want to do.

It should not even bother an optimizer.  The optimizer takes the operations
given by the programmer, in some cases applies transformations known to 
provide the same result, and optimizes the order.  Why should an integer
and a floating point number in the same location bother it, unless that
location is a register and the (expletives deleted) hardware has different
integer and floating registers?  But even that should not befuddle the
optimizer.
> -- 
>  Paul Smee               |    JANET: Smee@uk.ac.bristol
>  Computer Centre         |   BITNET: Smee%uk.ac.bristol@ukacrl.bitnet
>  University of Bristol   | Internet: Smee%uk.ac.bristol@nsfnet-relay.ac.uk
>  (Phone: +44 272 303132) |     UUCP: ...!mcvax!ukc!gdr.bath.ac.uk!exspes


-- 
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907
Phone: (317)494-6054
hrubin@l.cc.purdue.edu (Internet, bitnet, UUCP)

mac@harris.cis.ksu.edu (Myron A. Calhoun) (10/12/89)

In article <1654@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
>In article <1989Oct11.091619.18336@gdt.bath.ac.uk>, exspes@gdr.bath.ac.uk (P E Smee) writes:
>> In article <1989Oct10.185851.6490@agate.berkeley.edu> jerry@violet.berkeley.edu ( Jerry Berkman ) writes:
>< >Why not use equivalence?

 [several lines deleted]

>> Problem is, the Fortran standard *also* says that if your program tries...

 [several lines deleted]

>This is another example of those "gurus" who can not envision an intelligent
>user using the machine in an intelligent manner, and prevent that use.  I
>have deliberately used "type punning" on various machines, and I consider it
>an extremely useful tool.....

 [several lines deleted]

I agree wholeheartedly.  FORTRAN doesn't have PL/1's UNSPEC verb, yet
I have had occasion to want it.  And EQUIVALENCE provided it.
Calling a subroutine with "wrong" type parameters can also work:
   CALL NEWTYP (INTEGER,...)
       :::::
   SUBROUTINE NEWTYP (REAL,...)
--Myron
--
Myron A. Calhoun, PhD EE, W0PBV, (913) 532-6350 (work), 539-4448 (home).
INTERNET: mac@ksuvax1.cis.ksu.edu
BITNET:   mac@ksuvax1.bitnet
UUCP:  ...{rutgers, texbell}!ksuvax1!harry!mac

dik@cwi.nl (Dik T. Winter) (10/13/89)

(You could read the parent twice; I did not include it twice.)

In article <10950@riks.csl.sony.co.jp> diamond@ws.sony.junet (Norman Diamond) writes:
 > In article <475@idacrd.UUCP> desj@idacrd.UUCP (David desJardins) writes:
 > 
 > >      X = OR (I, 0).
 > >(The Cray FORTRAN compiler optimizes out the trivial OR instruction.)
 > 
 > Looks like the Cray Fortran compiler has a bug.  The result of OR(I,0)
 > should be an integer,

This ought to be in comp.lang.fortran; but nevertheless: no Mr Diamond.
OR is not a standard (generic) function in Fortran so Cray may play all
games with it (and defines it as typeless).
-- 
dik t. winter, cwi, amsterdam, nederland
INTERNET   : dik@cwi.nl
BITNET/EARN: dik@mcvax

khb%chiba@Sun.COM (Keith Bierman - SPD Advanced Languages) (10/13/89)

In article <1989Oct11.091619.18336@gdt.bath.ac.uk> exspes@gdr.bath.ac.uk (P E Smee) writes:


>Problem is, the Fortran standard *also* says that if your program tries
>to take the value of the variable using a different type than the type you
>used when you last stored into it, your program is invalid.  This is a
>polite way of saying (to the user) 'this trick may not work', and (to
>the

My quick peek into the document (pages 8-3 and 17-1..4ish) doesn't
make this obvious to me. Could you please quote chapter and verse ?

>
>Fortran equivalence was designed toallow reuse of storage on the early
>small memory machines -- not to allow type punning.  Usually you can
>get away with punning, but it doesn't always work and so is a bad habit.
>

On which systems (if any) have you seen this not work ?


Keith H. Bierman    |*My thoughts are my own. !! kbierman@sun.com
It's Not My Fault   |	MTS --Only my work belongs to Sun* 
I Voted for Bill &  | Advanced Languages/Floating Point Group            
Opus                | "When the going gets Weird .. the Weird turn PRO"

ok@cs.mu.oz.au (Richard O'Keefe) (10/13/89)

In article <4055@deimos.cis.ksu.edu>, mac@harris.cis.ksu.edu (Myron A. Calhoun) writes:
: In article <1654@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
: >This is another example of those "gurus" who can not envision an intelligent
: >user using the machine in an intelligent manner, and prevent that use.  I
: >have deliberately used "type punning" on various machines, and I consider it
: >an extremely useful tool.....

: I agree wholeheartedly.  FORTRAN doesn't have PL/1's UNSPEC verb, yet
: I have had occasion to want it.  And EQUIVALENCE provided it.
: Calling a subroutine with "wrong" type parameters can also work:
:    CALL NEWTYP (INTEGER,...)
:        :::::
:    SUBROUTINE NEWTYP (REAL,...)

I shall try to tell you what the point is in words that have but one
sound in them.  Those who write books that say what a tool like C means
want to help you make tools that can be used on more than one box.
I shall say it one more time:  "that can be used on more than one box".
A type pun is all but sure to work on at most one box.  This means that
those who write books that say what a tool like C means MUST tell you
not to trust type puns.  This does not mean that type puns will not
work on your box.  It just means that those who write books that say
what a tool like C means had to tell you that it might not work.  They
could not rule that the same pun must work on each box, since they do
not tell those who make each box what to do.  Nor do they tell YOU
what to do, just what you can TRUST.  If a type pun works on your box,
use it, but keep in mind that it may not work on aught else.

[PS:  UNSPEC is not a "verb" in PL/I, it is a "pseudo-function", and
 it is very far from being portable.  It's a _major_ pain when trying
 to port PL/I programs.
]

exspes@gdr.bath.ac.uk (P E Smee) (10/13/89)

In article <1654@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
>In article <1989Oct11.091619.18336@gdt.bath.ac.uk>, exspes@gdr.bath.ac.uk (P E Smee) writes:
>> In article <1989Oct10.185851.6490@agate.berkeley.edu> jerry@violet.berkeley.edu ( Jerry Berkman ) writes:
>< >
>< >Why not use equivalence?
>< >	INTEGER I
>< >	REAL X, IX
>< >	EQUIVALENCE (X,IX)
>< >
>< >The Fortran standard specifies that a REAL and INTEGER occupy the same space.
>> Fortran equivalence was designed toallow reuse of storage on the early
>> small memory machines -- not to allow type punning.  Usually you can
>> get away with punning, but it doesn't always work and so is a bad habit.
>
>This is another example of those "gurus" who can not envision an intelligent
>user using the machine in an intelligent manner, and prevent that use.  I
>have deliberately used "type punning" on various machines, and I consider it
>an extremely useful tool.  Now, I do not mind the compiler asking me if I
>really wanted to do it, but I object to anyone telling me that I CAN NOT
>use instructions that do what I want to do.

Trust me, 'cause I don't want to get into a long discussion of FORTRAN
in a C newsgroup.  There are an incredible number of things which may
cause aliasing in FORTRAN, some of it invisible to the compiler at any
given moment due to separate compilation of modules, and so the
optimizer needs all the help it can get.  '77 FORTRAN is even more
restrictive on the user as regards possible punning and aliasing than
'66 FORTRAN was, in order primarily to permit more reliable optimization.

The need for a construct to permit type punning is clear, particularly
if you're doing 'systemmy' work.  People working on the Algol compiler
on Multics (which does even more stringent, and cross-module, type
checking) resorted to writing little PL/1 routines which simply took
whatever they were given and passed it straight back,
unchanged(bitwise) -- and declared them in the Algol code as 'foreign'
('other language module, suspend type checking') 'takes integer returns
real'.  Lies, in other words.

I tend to like things which match PL/1's 'unspec' in concept.  This
provides an explicit instruction to the compiler, and (more
importantly) a warning to future maintainers of the code, that you are
about to willfully, knowledgeably, and intentionally, cheat the data
typing and conversion rules.  Every serious language should have such a
thing.  (Unfortunately, it seems that most don't, sigh...)

-- 
 Paul Smee               |    JANET: Smee@uk.ac.bristol
 Computer Centre         |   BITNET: Smee%uk.ac.bristol@ukacrl.bitnet
 University of Bristol   | Internet: Smee%uk.ac.bristol@nsfnet-relay.ac.uk
 (Phone: +44 272 303132) |     UUCP: ...!mcvax!ukc!gdr.bath.ac.uk!exspes

cik@l.cc.purdue.edu (Herman Rubin) (10/13/89)

In article <10950@riks.csl.sony.co.jp>, diamond@csl.sony.co.jp (Norman Diamond) writes:

			............................

> On the other hand, how many hardware architectures have instructions
> to transfer directly between integer registers and floating registers?
> Usually you have to store it to RAM and load it back anyway.

			............................

Most of the machines I am familiar with either have registers which can
be used for integer or floating point arguments.  Some of them have
an index type (shorter integer) but those can convert between short
integer and long..  These machines include VAX, PYRAMID, CDC 6x00
and descendents, CRAY, CYBER 205 and ETA 10, and even vector mode
on the IBM 3090.
-- 
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907
Phone: (317)494-6054
hrubin@l.cc.purdue.edu (Internet, bitnet, UUCP)

6sigma@polari.UUCP (Brian Matthews) (10/14/89)

In article <7675@cdis-1.uucp> tanner@cdis-1.uucp (Dr. T. Andrews) writes:
|henry@utzoo.uucp (Henry Spencer) writes:
|) If your compiler won't put unions into registers, complain to
|) your supplier.  
|Done, long ago. [...] The vendor's comment?  He said that they don't have
|to put unions in registers because "register" is just a hint, and they're
|free to do whatever they want to.

To which your response should be, "I'm free to do what I want also, and
now I'm going to find a new vendor."
-- 
Brian L. Matthews	blm@6sigma.UUCP

exspes@gdr.bath.ac.uk (P E Smee) (10/16/89)

In article <126279@sun.Eng.Sun.COM> khb@sun.UUCP (Keith Bierman - SPD Advanced Languages) writes:
>In article <1989Oct11.091619.18336@gdt.bath.ac.uk> exspes@gdr.bath.ac.uk (P E Smee) writes:
>
>
>>Problem is, the Fortran standard *also* says that if your program tries
>>to take the value of the variable using a different type than the type you
>>used when you last stored into it, your program is invalid.  
>
>My quick peek into the document (pages 8-3 and 17-1..4ish) doesn't
>make this obvious to me. Could you please quote chapter and verse ?
>
Section 17.3(2) -- (or, page 17.4, lines 15-18) 'When an entity of a
given type becomes defined, all totally associated entities of
different type become undefined.'  With 17.2(1) 'Execution of an
arithmetic, logical, or character assignment statement causes the
entity that precedes the equals to become defined.  These must, of
course, be taken in conjunction with the definition of what it means
for something to be defined, and with the fact that if your program
uses variables while they are undefined, your program is invalid.

From 17.1 it is clear that EQUIVALENCE may cause total association.
May also cause only partial association depending on what the
equivalanced entities are.  In particular, from 17.1.1 single
(non-array) integer, real, and logical values equivalenced in any mix
are totally associated.

>>
>>Fortran equivalence was designed toallow reuse of storage on the early
>>small memory machines -- not to allow type punning.  Usually you can
>>get away with punning, but it doesn't always work and so is a bad habit.
>>
>
>On which systems (if any) have you seen this not work ?
>
Honeywell Multics at certain optimisation levels.  Of course, since HIS
don't make them any more, that's a moot point.  I believe I recall
similar occasional problems under various flavours of IBM OSes, again
at particular optimisation levels.  Doesn't alter the fact that since
the standard makes it clear that it can be invalid, it's a bad habit.

-- 
 Paul Smee               |    JANET: Smee@uk.ac.bristol
 Computer Centre         |   BITNET: Smee%uk.ac.bristol@ukacrl.bitnet
 University of Bristol   | Internet: Smee%uk.ac.bristol@nsfnet-relay.ac.uk
 (Phone: +44 272 303132) |     UUCP: ...!mcvax!ukc!gdr.bath.ac.uk!exspes

exspes@gdr.bath.ac.uk (P E Smee) (10/16/89)

In article <1989Oct16.092936.142@gdt.bath.ac.uk> exspes@gdr.bath.ac.uk (P E Smee) writes:
>In article <126279@sun.Eng.Sun.COM> khb@sun.UUCP (Keith Bierman - SPD Advanced Languages) writes:
>>In article <1989Oct11.091619.18336@gdt.bath.ac.uk> exspes@gdr.bath.ac.uk (P E Smee) writes:
>>
>>
>>>Problem is, the Fortran standard *also* says that if your program tries
>>>to take the value of the variable using a different type than the type you
>>>used when you last stored into it, your program is invalid.  
>>
>>My quick peek into the document (pages 8-3 and 17-1..4ish) doesn't
>>make this obvious to me. Could you please quote chapter and verse ?
>>
In the previous posting, I quoted chapter and verse from the 77 FORTRAN
standard.  The 66 standard is even stricter.  EQUIVALENCE causes things
to become associated (full stop -- no fudging about partial or total
association) and says in 10.2.3.1 (5) [Variables and array
elements become undefined as follows:] When an associated entry
of different type becomes defined.

So, I'd say the 66 standard prohibits it completely, while the 77 standard
allows it in some cases (but only when the variables are not (loosely
speaking) of the same size).  The one interesting case which is explicitly
valid in 77 appears to be EQUIVALENCE of a REAL array of dimension 2 with
an COMPLEX variable, in which case REAL(1) would be the real part of
the COMPLEX and REAL(2) the imaginary part.
-- 
 Paul Smee               |    JANET: Smee@uk.ac.bristol
 Computer Centre         |   BITNET: Smee%uk.ac.bristol@ukacrl.bitnet
 University of Bristol   | Internet: Smee%uk.ac.bristol@nsfnet-relay.ac.uk
 (Phone: +44 272 303132) |     UUCP: ...!mcvax!ukc!gdr.bath.ac.uk!exspes

evil@arcturus.UUCP (Wade Guthrie) (10/19/89)

>In article <11242@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:

	However, C does provide "union" types that can be used for such 
	purposes.  Load the bit pattern into the integer union member 
	and extract it via the floating-point member.

lhf@aries5.uucp (Luiz H de Figueiredo) writes:

	Provided both members have the same size!  Otherwise, try

	union
	{
	 float f;
	 unsigned char b[sizeof(float)];
	};

I thought that the standard said (as opposed to what I remember reading
in K&R I) that members of unions do NOT have to have zero offset?  In
this case, none of the above work (and, BTW, breaks a lot of existing
code).

Do I completely misunderstand what the standard said, or is the stuff
above just not portable to ANSI conformant compilers (God, I didn't mean
for that to sound as snotty as it did -- please take that as a neophyte
asking an innocent question).


Wade Guthrie
evil@arcturus.UUCP
Rockwell International
Anaheim, CA

(Rockwell doesn't necessarily believe / stand by what I'm saying; how could
they when *I* don't even know what I'm talking about???)

karl@haddock.ima.isc.com (Karl Heuer) (10/21/89)

In article <6310@arcturus> evil@arcturus.UUCP (Wade Guthrie) writes:
>I thought that the standard said (as opposed to what I remember reading
>in K&R I) that members of unions do NOT have to have zero offset?

The pANS guarantees that a pointer to a union, suitably cast, points to each
of its members, and vice versa.

It also says that the behavior is undefined if you use a union for punning.
(What else could it say?  You can't close your eyes and pretend that the
behavior is predictable!)  Since you already know your program isn't portable,
you needn't worry about this.

It may be that the undefined-behavior clause would permit an implementation
where punning doesn't work and differently-typed union members don't overlap,
provided that appropriate code is generated when casting to/from a union type.
This may be the source of the rumor you heard.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

kremer@cs.odu.edu (Lloyd Kremer) (10/21/89)

In article <11242@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:
>
>	However, C does provide "union" types that can be used for such 
>	purposes.  Load the bit pattern into the integer union member 
>	and extract it via the floating-point member.


Another way would be to back off one level of indirection, and transfer
the bit pattern by means of pointers to the respective objects.

Example:
	float f;
	int i;

	/* assign f */
	i = *(int *)&f;  /* transfer bit pattern from f to i */

-- 
					Lloyd Kremer
					...!uunet!xanth!kremer
					Have terminal...will hack!

bill@twwells.com (T. William Wells) (10/24/89)

In article <14939@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
: It may be that the undefined-behavior clause would permit an implementation
: where punning doesn't work and differently-typed union members don't overlap,
: provided that appropriate code is generated when casting to/from a union type.
: This may be the source of the rumor you heard.

Actually, the standard is quite unambiguous in asserting that the
members of a union overlap. But it doesn't say beans about by how
much.

---
Bill                    { uunet | novavax | ankh | sunvice } !twwells!bill
bill@twwells.com

thorinn@skinfaxe.diku.dk (Lars Henrik Mathiesen) (10/27/89)

bill@twwells.com (T. William Wells) writes: <In article
<14939@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer)
<writes:
<: It may be that the undefined-behavior clause would permit an
<: implementation where punning doesn't work and differently-typed union
<: members don't overlap, provided that appropriate code is generated
<: when casting to/from a union type.  This may be the source of the
<: rumor you heard.

<Actually, the standard is quite unambiguous in asserting that the
<members of a union overlap. But it doesn't say beans about by how
<much.

If this is meant in the sense that inverting all the bits of one union
member is guaranteed to invert at least one bit of every other member,
then I think that the committee has overconstrained the language a
bit. As discussed before in the context of capability machines,
objects of pointer type may want to live in another address space than
objects of basic type.

Another reason to make union members start at an offset would be to
allow objects (e.g., chars) which are smaller than a machine word to
be placed in the same position in a memory word as in a register; in a
big-endian architecture that position will not have the same byte
address as the containing word.

A compiler optimizing for fast-but-space-consuming code might want to
do this for all ``small'' structure members; however, the standard
forbids holes at the start of structures. This means that given

	struct s { signed char c, int i} s;
	union  u { signed char c, int i} u;
	void *p;

these are guaranteed to hold:

(1)	&s.c == (signed char *)(void *)&s;
(1')	&((struct s *)p)->c == (signed char *)p;
(2)	&u.c == (signed char *)(union u *)&u.i;

whereas the compiler is free to put u.c at an offset so that

(3)	&u.c != (signed char *)(void *)&u.i;

The difference between (2) and (3) is that the standard demands that
the compiler can cast between pointer-to-union and pointer-to-member
(even if there's an offset). The difference between (1) and (3) is
that the standard forces s.c to be at offset zero.

Note that even if the no-initial-hole constraint were lifted,

(4)	&s.c == (signed char *)&s;
(4')	&((struct s *)p)->c == (signed char *)(struct s *)p;

could still be guaranteed (with some work from the compiler _if_
initial holes were used). The relevant sentences (in the May 88 draft)
go: ``A pointer to a structure object, suitably cast, points to its
initial member (or if that member is a bit-field, then to the unit in
which it resides), and vice versa.  There may _therefore_ be unnamed
holes within a structure, but not at its beginning, as necessary to
achieve the appropriate alignment.'' (My emphasis). It seems to me
that the no-initial-hole rule is a conclusion rather than a deliberate
decision.

Therefore I wonder which, if any, of the following it was that the
Committee intended:
	a) ``Suitably cast'' does not involve changing the byte
address of a pointer, only its type; in other words, an intermediate
void pointer can validly be used. [In this case, all union members
have to start at the same byte address too, as the language used for
unions is similar in regard to the casting although the no-hole rule
is not explicit stated.]
	b) There is so much code out there which does not explicitly
cast structure pointers (when used as function arguments, for example)
that this guarantee must be given; however, that is not the case for
union pointers[?!].
	c) When a union type has several members with structure type,
and each of those structures have an initial member with the same
common type, it should be possible to use those initial members
interchangeably. [This would be very useful for discriminated unions,
however, the comment about unions from a) above must apply here too
for that to work.]
	d) RISCs are fast enough already, let's not allow them to
optimize too much [:-)].

In my opinion, only c) above is totally acceptable, and if that was
the reason, it might have been formulated more directly. Anyway, if I
ever get my hands on a current Draft (or even Standard), Rationale,
Response and Interpretations document, and they don't cover this
better, I may cook up a Request for Interpretation (or whatever the
term is).

--
Lars Mathiesen, DIKU, U of Copenhagen, Denmark      [uunet!]mcvax!diku!thorinn
Institute of Datalogy -- we're scientists, not engineers.      thorinn@diku.dk