2016-05-13 48 views
1

我一直在为此苦苦挣扎太久。使用sscanf找到bug的来源

比方说,我有这个最小代码:

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产生这样的输出,符合市场预期:

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

现在我有这5嵌入到具有几千行的项目中的线条,以及许多包括...

编译,运行,现在的输出是:

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

我可以用什么策略来定位这一矛盾的根源?

编辑: export LC_ALL=C (or LC_NUMERIC=C); ./a.out似乎解决我的问题

+0

您正在使用什么平台? Atmel AVR有什么机会或类似的东西?在某些平台上启用'printf' /'scanf'中的浮点支持需要链接这些函数的特殊版本。 – AnT

+0

在Ubuntu 16.04上使用cmake进行配置,gcc 5.3.1,没有交叉编译... – neok

+3

另外,这个大项目中的locale设置是不同的吗?例如,在某些语言环境中'.'不被认为是小数部分的有效部分(','用来代替'.') – AnT

回答

2

这可能是由不同的语言环境中的测试,并在您的目标应用程序引起的。我能够重现上coliru:

使用:

setlocale(LC_ALL, "cs_CZ.utf8"); 

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

您可以在此于是找到一些解决办法:

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

[编辑]

带的解决方案,但既然你用C++标记了这个问题,那么为什么不使用std :: stringstream并用适当的语言环境灌输它(参见上面的SO链接)。

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); 
+0

谢谢marcinj,我想我不能在运行时改变这种行为,我可以吗? Coliru似乎确实非常方便,我会牢记... – neok

+0

@neok uselocale似乎为此工作 – marcinj