2

I have some C code which converts an ASCII string to a double with strtod(...). The program gets compiled for x86 (debugging), ARM and PowerPC (embedded target systems). The ARM board is actually a BeagleBoard xM running the Debian which is available for it.

I've discovered that strtod() does not convert the values correctly on the ARM / Debian system. In fact all values I tried came out as 0.000.

To demonstrate, I wrote the following very simple test program:

#include <stdio.h>
#include <stdlib.h>

int main(const int argc, const char **argv)
  {
  const char myString[] = "123 ";
  char *myEnd1 = NULL;
  char *myEnd2 = NULL;

  float  fValue = 0;
  double dValue = 0;

  dValue = atof(myString);

  printf(   "Using atof():\n"
            " String:  %s\n"
            " Double:  %lf\n",
             myString,
             dValue                           );

  fValue = strtof(myString, &myEnd1);
  dValue = strtod(myString, &myEnd2);

  printf(   "Using strtof() / strtod():\n"
            " String:  %s\n"
            " Float:   %f (%d)\n"
            " Double:  %lf (%d)\n",
            myString,
            fValue, (myEnd1 - myString),
            dValue, (myEnd2 - myString)             );

  return 0;
  }

All were compiled on an x86 PC running Ubuntu (actually in a virtual machine). I have cross-compiler toolchains for PowerPC and ARM compilation.

On the x86 and PowerPC systems, the output is as expected, i.e.:

Using atof():
 String:  123 
 Double:  123.000000
Using strtof() / strtod():
 String:  123 
 Float:   123.000000 (3)
 Double:  123.000000 (3)

However, when run on the BeagleBoard, I get this:

Using atof():
 String:  123
 Double:  0.000000
Using strtof() / strtod():
 String:  123
 Float:   -0.372039 (3)
 Double:  0.000000 (3)

Huh??? Did I miss something stupid? Note that the "myEnd" pointers are just there to show that strtod() and strtof() did find the first non-numeric character and therefore the end of the number. They report the correct number of characters in the number in both cases (3), yet the converted value is wrong. I don't think it's a locale problem as there is no decimal point to get confused about.

EDIT:

I just recompiled the test program with the option "-static". This made the binary much bigger, of course, but now it works correctly on the target ARM platform.

I'm a bit hazy on the way libraries work. Also, I can't remember exactly how I built my cross compiler toolchain. It was probably not built from the same source as the Debian Linux actually installed on the target board.

So, does the inexplicable behavior of atof(), etc, mean a library "expected" by the dynamically-linked executable is not the same as the actual library on the system? I'm surprised that this didn't cause worse problems. We've been running this system for a year, and so far this is the only strange bug we have encountered.

Jeremy
  • 1,083
  • 3
  • 13
  • 25
  • 3
    Probably unrelated: `%f` is for printing a `double`. There is no `%lf` in `printf` and no format for a `float` (you cannot pass a `float` through varargs). – n. m. could be an AI Sep 10 '14 at 03:56
  • Using "%e" rather than "%f" may given a little more info to "Double: 0.000000". – chux - Reinstate Monica Sep 10 '14 at 05:18
  • Interesting, I thought '%lf' looked odd. I actually had '%f' but wasn't sure it handled doubles, so I looked up the printf format codes (in a hurry) and found %lf "on the internet". Obviously, that page was wrong! Anyway, it made no difference to the output so I think it was being ignored anyway. See Edit. – Jeremy Sep 11 '14 at 05:45
  • @nm Since C99, `%lf` prints a double. (Of course, he shoudl still actually use `%f` as it works in C90) – M.M Sep 11 '14 at 08:05
  • `%d` is the wrong format specifier for `(myEnd1 - myString)`. In C99 it is `%td`. In C90 there was no format specifier, so you should write `(int)(myEnd1 - myString)` etc. – M.M Sep 11 '14 at 08:06
  • Perhaps the linker did not link the floating point libraries (Turbo C had this bug). Try doing `#include ` and calling a math function; and/or make sure you explicitly link the floating point library in the linker command. – M.M Sep 11 '14 at 08:08
  • Thanks @Jeremy you saved my day :-) Furthermore I found out that if the cross-compiler is building for gnueabi but the embedded ARM is a armhf, the problem occurs. After changing my toolchain to crosscompile for gnueabihf it was also solved, even without "-static" – Achim Jul 20 '23 at 14:21

0 Answers0