CompuServe Thread

#Unions

6 messages in this thread
#44817From: ShraddhanDec 18, 1994 8:34 AM
I wold like to have a convenient way of handling double floats so that I can refer to them either as a double float or as two long words, without constant type-casting. I have tried using: #define High 0 #define Low 1 union DoubleFloat { double dp; // A double float number long DP[2]; // The same number as two longs }; struct DoubleFloat ValDPFloat; but I find that ValDPFloat.DP[High] is stored _after_ ValDPFloat.dp rather than at the same address, thus defeating the whole point. I am using DICE. Is this a problem with DICE or with me? Regards, Shraddhan (via AP from Hertfordshire, England)
#44832From: ShraddhanDec 19, 1994 1:44 PM
A further question, related to the above, is how do I define, initialise and access an array of unions? I would like to have an array of double floats, but I need to initialise them as pairs of longs, for the sake of guaranteed precision to the last bit. How would C know to which element of the union I was referring? -i.e the pair of longs, or the double float? Regards, Shraddhan (via AP from Hertfordshire, England)
#44835From: Freddy PotargentDec 19, 1994 4:27 PM
Hi again Shraddhan, Declaring an array of unions and accessing the fields is the same as if it were structures. For instance (see my other message for declaration of the union): union DoubleFloat df_array[10]; Initialising all elements to 1.0: for (i = 0; i < 10; ++i) { df_array[i].dp = 1.0; } Or using the pair of longs: for (i = 0; i < 10; ++i) { df_array[i].li[0] = 0x3ff00000; df_array[i].li[1] = 0x00000000; } — Freddy
#45064From: Doug WalkerJan 4, 1995 8:55 PM
Hi Shraddhan – When using static initialization on an array of unions, treat it like you were initializing the first element of the union. There is no way in C to statically initialize elements other than the first. Also note that what you are doing with the union is technically illegal. If you store a value in a given member of a union, it is undefined what happens if you read from another element. Unions are intended to allow you to save space by overlaying data items, not to "type pun" (as compiler writers call it) by overlaying one type on another. The reason it's illegal is that the compiler may decide to keep the value you are writing in a register. It is allowed to do this as an optimization. When you read from the other element of the union, you get whatever happens to be in memory there, not what's in the register. There are situations with the SAS/C optimizer that can cause this. You'll be relatively safe if you declare your union with the "volatile" keyword, but this will kill ALL optimizations having to do with it. Personally, I'd use some macros: #define LONGPTR(x) ((long *)&(x)) #define HIGH(x) (LONGPTR(x)[0]) #define LOW(x) (LONGPTR(x)[1]) This method has the disadvantage of only working on lvalues (variables) and not on constants, of course. You can make it work for constants by a kludge: declare an external double (here called "xxx") and do #define HIGH(x) ((xxx=(x)), (LONGPTR(x)[0])) #define LOW(x) ((xxx=(x)), (LONGPTR(x)[1])) This takes advantage of the comma (,) operator, which simply evaluates its first operand and performs any side effects, then evaluates its second operand. The result of the operation is the value of the second operand. –Doug
#44834From: Freddy PotargentDec 19, 1994 4:25 PM
Hi Shraddhan, The example _should_ work so I suspect an error in DICE. Check out the following program (compiled with the GNU-compiler) and its output: #include <stdio.h> union DoubleFloat { double dp; long li[2]; }; union DoubleFloat df1; int main (void) { printf ("sizeof (df1) : %2d address of df1 : %08p\n" "sizeof (df1.dp): %2d address of df1.dp : %08p\n" "sizeof (df1.li): %2d address of df1.li[0]: %08p\n" " address of df1.li[1]: %08p\n", sizeof (df1), &df1, sizeof (df1.dp), &df1.dp, sizeof (df1.li), &df1.li[0], &df1.li[1]); df1.dp = 1.0; printf ("%lf => %08lx %08lx\n", df1.dp, df1.li[0], df1.li[1]); df1.li[0] = 0x3ff80000; df1.li[1] = 0x00000000; printf ("%08lx %08lx => %lf\n", df1.li[0], df1.li[1], df1.dp); } And the output: sizeof (df1) : 8 address of df1 : 0x7d40ff4 sizeof (df1.dp): 8 address of df1.dp : 0x7d40ff4 sizeof (df1.li): 8 address of df1.li[0]: 0x7d40ff4 address of df1.li[1]: 0x7d40ff8 1.000000 => 3ff00000 00000000 3ff80000 00000000 => 1.500000 Which is the correct output (and the output you expect). Hope this helps, — Freddy
#44840From: Mal LansellDec 20, 1994 8:34 AM
Shraddhan, Somehow my reply yesterday seems to have got lost! The problem is not with dice, but with your declaration of ValDPFloat. You have defined it as struct DoubleFloat ValDPFloat; whereas you should use union DoubleFloat ValDPFloat; Dice was taking your specification of DoubleFloat, and turning it into a struct, thus making DP follow on from dp, rather than share the same memory space Mal Binary Dreams