最近再用ADS1.2调试软件时,发现用sprintf()函数将浮点数转换为字符串输出时无法正确显示,经过多方查找资料,问题最终得到解决。
产生问题的原因主要是没有配置地域化信息。printf函数是用于格式输出的,这个大家都知道,但是大家要注意的是,printf函数不仅仅是输出,而且还有格式输出的功能,格式的形式不仅仅是 %d,%f,%x 这些格式化控制符,还包括小数点的表示形式,时间的表示形式,货币的表示形式。比如,我们国家用“.”表示小数点,但有些国家用“,”表示。还有时间,我们习惯是 年 月 日,但有些国家或地区是 月 日 年,甚至是 日 月 年,因此,为了让程序在各个国家或地区使用,必须对printf函数的使用环境作本地化,也就是让printf函数输出符合该国家/地区习惯的格式。
由此引入了 setlocale 函数,从这个函数的名称就可以看出它的作用,set(设置) locale(地区),当然,该函数不仅仅服务于printf,函数原型定义在 locale.h 文件中,因此在使用 setlocale函数时必须 #include <locale.h>。
如果想要在ADS1.2中使用sprintf函数并想得到预期的结果,我们需要调用setlocale函数,具体如下:
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
void system_init(void)
{
......
setlocale(LC_ALL,"C"); //设置本地区域
sprintf(......);
......
}
至于 setlocale 函数的原型与参数,包含在ADS1.2的安装目录ADSv1_2/Include下的locale.h文件中,以下进行列出:
原型:char *setlocale(int category, const char * locale);
category是五个之一的名字,类别如下:
LC_COLLATE (设置字符串排序和比较功能)
LC_CTYPE(设置字符分类和大小写区分功能)
LC_MONETARY(设置货币格式)
LC_NUMERIC(设置数字表示格式)
LC_TIME(设置日期和时间的表示格式)
LC_ALL(设置所有的类别)
locale 参数是一个指向字符串的指针,用于设置指定的区域。其中最常用的是locale.h中已经定义的 "C"字符串常量, 表示使用标准的区域设置,这个标准的区域设置就可以满我们的要求了。通常,一般的编译器都会使用这个标准的区域设置,这也就是大家为什么容易犯这个错误的原因,以为什么都不用干就可以使用pritnf了,因为以前是编译器帮你做了,但也有不帮你的时候, 当然,如果对C语言足够了解的话就知道是什么原因了,因为区域设置函数是ANSI C中的一部分,出现这种问题后应该能够想到是什么原因。
附:__rt_lib_init()函数是用来初始化运行时库的,它同时也初始化了本地区域。__rt_lib_init()函数调用了setlocale()函数,遇到的sprintf函数无法输出浮点数小点的问题,其本质就是因为没有调用setlocale()函数初始化本地区域。更多信息可以查看ARM Developer Suite Compilers and Libraries Guide。
致谢:在总结过程中,摘抄了网友 lwtlwt 帖子的部分内容,在此表示感谢。