2

I'm trying to write a double to a binary file, but can't figure out how to convert it to a char[] in a portable way. I'd like to write it in the IEEE double precision format, big endian, and convert it back to the current platform's format.

Thanks for the help.

Jack Maloney
  • 527
  • 2
  • 5
  • 18
  • As the representation of float is not defined by the standard **in general** and left to the implementaion, there is _no_ portable way. However, if your implementation uses IEEE754 floating point (`__STDC_IEC_559__` defined), you can at least avoid bit-twiddling. – too honest for this site Aug 04 '15 at 20:47
  • Do you need portable code or code for some particular platform? – David Schwartz Aug 04 '15 at 20:49
  • Portable code... I guess. By that I mean I don't have any existing implementation that only works on a specific platform. – Jack Maloney Aug 04 '15 at 20:55
  • @Olaf what do you mean by "you can at least avoid bit-twiddling"? – Jack Maloney Aug 04 '15 at 20:56
  • COnverting the implementation's representation to/from ISO format? – too honest for this site Aug 04 '15 at 21:00
  • @JackMaloney Then you need a portable IEEE double precision float library. Use a search engine. – David Schwartz Aug 04 '15 at 21:08
  • 1
    @JackMaloney: In general, a binary format is a bad idea for portable data-interchange (and for debugging, btw.). There are good reasons JSON and XML have become widely accepted now, even in the Windows-world of proprietary binary formats. – too honest for this site Aug 04 '15 at 21:16
  • Yeah, except I'm using this for an interpreter, and I want a binary format for it's speed. I could always just write the float as a string and read it in using `strtod` or something, and use binary for everything else. Preferably I'd like to have the whole thing in binary though. – Jack Maloney Aug 04 '15 at 21:23
  • @Pynchia: There is no advantage in either endianess, as the data has to be read into a variable anyway. – too honest for this site Aug 04 '15 at 21:27
  • @Pynchia the problem isn't the file format, it's the conversion between the platform's format and the file format. – Jack Maloney Aug 04 '15 at 21:27
  • @JackMaloney: An interpreter would use text actually. Otherwise you can first convert internally to bytecode. Sounds as if you are re-inventing the wheel for the 1000thed. – too honest for this site Aug 04 '15 at 21:28
  • @Olaf it's a bytecode interpreter. I would like the bytecode format to be binary because its fast. I also have a text version of the bytecode that is compiled/assembled into the binary format. I'm not sure what the problem with that is. – Jack Maloney Aug 04 '15 at 21:33

2 Answers2

1

Various approaches:

1) Use a string. If FLT_RADIX is 10, use fprintf(outf, " %.*e", DBL_DECIMAL_DIG-1, x), otherwise use fprintf(outf, " %a", x) (Ref). Use fscanf(inf, "%lf", &x) to read back. ("%la" has same effect)

2) Use a union and assume double format is IEEE double precision binary format, maybe also use defined endian and *nix: htonl()

union d2a {
  double d;
  unsigned char uc[sizeof double];
} u;

u.d = x;
ToNetworkEndian(u.uc);
fwrite(u.uc, 1, sizeof u.uc, outf);

fread(u.uc, 1, sizeof u.uc, inf);
FromNetworkEndian(u.uc);
x = u.d;

3) Write a lot of code to covert compiler's non-standard double to IEEE taking into account: different precision, range, wobbling precision, +/- 0, sub-normals, etc.

Recommend option 1

Community
  • 1
  • 1
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
-3

C and C++ have an fread and fwrite, which just copy the bytes from your specified location in a specified chunk size to a specified file stream and vice versa... You wouldn't have to convert to a char[]

  • Yeah, the only problem is endianness... Unless I'm mistaken about how this would work. – Jack Maloney Aug 04 '15 at 20:54
  • You're not mistaken. Here's how I'd go about it... Regardless of platform, whenever you write to file, just use fwrite. You'll copy the bytes in linear order into a binary file. Whenever you read, write a wrapper function that flips your byte order. – Dushyant Srikant Aug 04 '15 at 21:00
  • 1
    @DushyantSrikant Not good enough. Two different platforms could write the float to disk in two different formats. To be portable, what gets written to disk (or alternately, sent over a network) has to be in a known format. – dbush Aug 04 '15 at 21:03
  • @JackMaloney: No, the problem is also alignment and the implementation's representation of floating point values. The standard does **not** enforce a specific representation. It just details how a ISO compliant version has to behave. And even with that, there might be padding. E.g. MSVC and gcc us different `sizeof` for `long double`, but the same FPU (i.e. the same bit-representation). THe difference is just padding. – too honest for this site Aug 04 '15 at 21:03
  • @Olaf How would one go about converting non-ISO floats to the ISO format? – Jack Maloney Aug 04 '15 at 21:09
  • @JackMaloney: Well, you asked about a portable way. That includes systems with non-ISO floating points. If not, you should restrict your question to internal ISO representation, still leaving alignment/padding issues. – too honest for this site Aug 04 '15 at 21:13
  • @Olaf So what you're saying is that there is no portable way to do this? And what would the alignment/padding issues be? – Jack Maloney Aug 04 '15 at 21:19
  • 1
    @JackMaloney: Please think about the implications of "**implementation defined**" with regard of portability, aka "**not implementation dependent**". Just read the standard, you might start [here](http://port70.net/~nsz/c/c11/n1570.html#6.2.6), but read further. – too honest for this site Aug 04 '15 at 21:22