1

I've been struggling with this for too long.

Let's say i have this minimal code:

test.cxx

#include <iostream>
#include <cstdio>

int main (int argc, char *argv[])
{
  const char *text = "1.01 foo";  
  float value = 0;  
  char other[8];

  int code = sscanf(text, "%f %7s", &value, other);
  std::cout << code << " | " << text << " | => | " << value << " | " << other << " | " << std::endl;

  return 0;
}

$ g++ test.cxx; ./a.out produces this output, as expected:

$ 2 | 1.01 foo | => | 1.01 | foo |

Now I have these 5 lines embedded into a project with several thousand lines, and lots of includes ...

Compiling, running, and the output is now:

$ 2 | 1.01 foo | => | 1 | .01 |

What strategy could I use to locate the source of this inconsistency ?

EDIT: export LC_ALL=C (or LC_NUMERIC=C); ./a.out seems to solve my problem

neok
  • 802
  • 8
  • 14
  • What platform are you using? Atmel AVR by any chance or something like that? On some platforms enabling floating-point support in `printf`/`scanf` requires linking-in a special version of these functions. – AnT May 13 '16 at 18:04
  • Configuring with cmake on Ubuntu 16.04, gcc 5.3.1, no cross-compilation ... – neok May 13 '16 at 18:06
  • 3
    Also, could it be that locale settings in that big project are different? For example, in some locales `.` is not considered a valid part of decimal fractions (`,` is used instead of `.`) – AnT May 13 '16 at 18:08
  • Ooh i'm going to dig into that ! – neok May 13 '16 at 18:09

1 Answers1

2

It might be caused by a different locale in your test and in your destination application. I was able to reproduce it on coliru:

by using:

setlocale(LC_ALL, "cs_CZ.utf8");

http://coliru.stacked-crooked.com/a/5a8f2ea7ac330d66

You can find some solutions in this SO:

sscanf() and locales. How does one really parse things like "3.14"?

[edit]

Solution with uselocale, but since you tagged this question with C++ then why not use std::stringstream and imbue it with proper locale (see link to SO above).

http://coliru.stacked-crooked.com/a/dc0fac7d2533d95c

  const char *text = "1.01 foo";  
  float value = 0;  
  char other[8];

  // set for testing, sscanf will assume floating point numbers use comma instead of dots
  setlocale(LC_ALL, "cs_CZ.utf8");

  // Temporarily use C locale (uses dot in floats) on current thread
  locale_t locale = newlocale(LC_NUMERIC_MASK, "C", NULL);
  locale_t old_locale = uselocale(locale);

  int code = sscanf(text, "%f %7s", &value, other);
  std::cout << code << " | " << text << " | => | " << value << " | " << other << " | " << std::endl;

  // Go back to original locale
  uselocale(old_locale);
  freelocale(locale);
Community
  • 1
  • 1
marcinj
  • 44,446
  • 9
  • 70
  • 91
  • Thank you marcinj, i guess I cannot change this behavior at run time, can I ? Coliru seems indeed very handy, I'll keep that in mind ... – neok May 13 '16 at 18:24