Add XDR support (only built #if cygwin, for now)

Charles Wilson cygwin@cwilson.fastmail.fm
Fri Feb 26 21:51:00 GMT 2010


Corinna Vinschen wrote:
> On Feb 26 13:52, Charles Wilson wrote:
>> Corinna Vinschen wrote:
>>> If _DOUBLE_IS_32BITS is set, call xdr_float from xdr_double.
>> Hmmm...actually, I think this is wrong.  The XDR stream format of a
>> double is supposed to be universal, and is 8 bytes long. If I have an
> 
> Good point.  The IEEE float and double formats are well known, though,
> so shouldn't it be quite simple to convert a 32 bit IEEE float into 64
> bit and vice versa?  Well, that's going a step too far for now, I guess,
> but it spoils interoperability a bit.
> 
>> I think in this case double support should just be removed.
> 
> Yes, I guess so, unless we have generic code to convert 32 bit to 64 bit
> FP and vice versa.  Does anybody know?

Well, the typical way you use XDR in data interchange is you define a
struct:

typedef struct {
   int    foo;
   double bar;
   float  baz;
} my_struct_t;

Then, you define a conversion function (if you're lucky, you can simply
chain the existing primitive xdr_* functions):

extern bool_t xdr_my_struct_t (XDR *, my_struct_t *);

bool_t xdr_my_struct_t (XDR *xdrs, my_struct_t *mys)
{
  return (
      xdr_int            (xdrs, &(mys->foo)) &&
      xdr_double         (xdrs, &(mys->bar)) &&
      xdr_float          (xdrs, &(mys->baz)));
}

Now, here's the important part: encode/decode directionality is
controlled by the contents of the *xdrs variable.  So, you use //the
same function// for both encode and decode.  AND, you use that identical
function on both the receiving platform, and the sending platform.

Now, suppose the receiving platform has _DOUBLE_IS_32BIT, but the
sending platform does not (or vice versa).  No matter what kind of
translation you do under the hood, you're going to lose data and *not
know about it*.

This is bad.

If you are trying to design a protocol to communicate between platforms
with different ideas of what constitutes a 'double', then...don't send
doubles.  Design a different protocol that only uses floats.


This is the same problem that many protocols (and XDR implementations)
ran into with regards to 'long' with the advent of 64bit platforms. The
whole XDR idea was designed around encoding data as sequences of encoded
longs (where, everybody knows, that a long is and always will be 32bits.
And nobody will ever need more than 640k RAM).

Oops.

So, enter the width-specific encode/decode functions.  And in this
implementation, the core datastream functions:
   (*(xdrs)->x_ops->x_putlong)(xdrs, longp)
   (*(xdrs)->x_ops->x_getlong)(xdrs, longp)
take special care such they are usable for all integer data types whose
native width is <= 32bits.  However, if the "long" value being encoded
is actually 64bits, and CAN'T be represented in only 32bits, then the
encode/decode function fails (returns FALSE).



And in general, it is recommended to use the width-specific functions
when possible, but most importantly to avoid using xdr_long/xdr_u_long
if you can help it (I don't know of any platforms where int, short, or
char might be > 32bits, but if there are any, that'd also run into the
same problem; it's just a lot more likely to happen with 'long').  This
is typical of modern XDR implementations.


The analogous "solution" -- always treat the wider data type as if it
were the narrower one, and fail when the value won't fit -- isn't
possible here, because xdr_double() is already part of the published XDR
API.  And we really don't want to cripple all XDRs to always downgrade
doubles into floats.

So, I don't think we need some conversion function.  It's better for the
client program to just fail to compile if you attempt to use a protocol
that requires true doubles.  And if your protocol only requires
floats...then use floats.

--
Chuck



More information about the Newlib mailing list