C++中char[]转float异常:atof/sscanf丢失小数部分求助
问题出在区域设置(Locale)上!
看你的输出里的1,000就明白了——你的系统当前用逗号作为小数点分隔符,但你从串口读进来的字符串是1.86(用点做小数点)。sscanf和atof这些数值解析函数都会遵循系统的区域设置(locale)规则,所以它们把.当成了无效的分隔符,只读取了整数部分1,这就是为啥你得到的结果丢失了小数部分。
验证这个问题的小技巧
你可以先打印当前locale的信息来确认:
#include <clocale> // ... std::cout << "Current locale: " << setlocale(LC_ALL, NULL) << std::endl;
输出大概率会是类似es_ES.UTF-8这类使用逗号做小数点的locale。
解决方法(推荐第一种)
方法1:临时切换到C标准Locale
C标准locale默认使用点作为小数点分隔符,你可以在解析数值前临时切换,解析完成后再恢复原来的设置(如果程序其他部分需要依赖系统locale的话):
#include <locale> // ... // 保存当前的locale设置 std::locale original_locale = std::locale(); // 切换到C标准locale(强制用点做小数点) std::locale::global(std::locale("C")); // 现在执行你的解析操作 std::cout << "Applying sscanf " << std::endl; sscanf(data, "%f", &n1); printf("%.3f%s", n1, " "); n1 = atof(data) * 0.5f; printf("%.3f", n1); std::cout << "n1 value which have data turn it " << n1 << std::endl; // 恢复原来的locale设置 std::locale::global(original_locale);
方法2:替换字符串中的小数点
如果你确定系统locale一直使用逗号作为小数点,也可以先把输入字符串里的.替换成,再解析:
// 遍历字符串,把第一个.换成, for (int i = 0; data[i] != '\0'; ++i) { if (data[i] == '.') { data[i] = ','; break; } } // 再执行解析 sscanf(data, "%f", &n1); n1 = atof(data) * 0.5f;
额外确认:你的串口读取逻辑没问题
看你的serial_read函数,最后设置了data[count] = 0,这保证了data是正确的C风格终止字符串,这部分没有问题,不用修改。
用方法1修改后,1.86会被正确解析为1.86,乘以0.5后得到0.93,你的输出就会符合预期了。
内容的提问来源于stack exchange,提问作者bgarcial
相关产品推荐
相关产品推荐

