[更新:Cygwin运行库“newlib”存在处理十六进制浮点数输入的错误。截至2021年4月,已经提交了修复,但尚未发布。]
我看不出你的代码有任何问题。当我在我的Linux系统上编译和运行它时,输出结果是:
Example 1.2 buffer -> 0x1.3333333333333p+0
Example 1.2 scanf <- 1.2
%a
格式说明符是在C99中引入的,后来并入了C++11。对于
sprintf
调用,
"%a"
是一个有效的
double
类型参数格式,而对于
sscanf
调用,
"%la"
是一个有效的
double*
类型参数格式。
gcc(或g ++)的版本与问题无直接关系。gcc只是编译器;
sscanf
函数是由运行时库实现的。
当我在Windows 7上的Cygwin下编译和运行您的程序时,我得到与您相同的错误输出。Cygwin使用“newlib” C库,它不同于大多数Linux系统上使用的glibc库。
如果您正在使用MinGW安装的gcc,则我记得它使用Microsoft C库。Microsoft对1990年之后的C标准的支持不太好,因此如果它不能正确实现
sscanf
的
"%la"
格式,这也就不足为奇了。
请注意,您不需要使用
"%la"
进行十六进制输入。对于
*scanf
函数,
a
、
e
、
f
和
g
格式说明符都是等效的,并且都可以接受十进制或十六进制浮点输入。因此,您应该能够使用:
sscanf(buffer, "%lf", &x);
但如果"%la"
不能使用,那么"%lf"
可能也无法正常工作。
sscanf
函数返回一个int
类型的结果,表示成功扫描的项目数。您应始终检查该结果。(尽管如果我的Cygwin实验是任何指南的话,在这种情况下它不会有任何好处;sscanf
返回1
,但仍将x
设置为0.0
。)
底线:您的代码没问题,但您可能正在使用不支持您尝试执行的操作的运行时库。
这里有另一个程序(它是纯C,但应该可以作为C++使用),它应该提供更多信息。sprintf
返回写入的字符数;sscanf
返回读取的项目数。
#include <stdio.h>
int main(void) {
char buffer[40];
char leftover[40];
double x = 5.0;
int sprintf_result = sprintf(buffer, "%a", 1.2);
printf("sprintf returned %d, buffer = \"%s\"\n", sprintf_result, buffer);
int sscanf_result = sscanf(buffer, "%lf%s", &x, leftover);
printf("sscanf returned %d, x = %f", sscanf_result, x);
if (sscanf_result >= 2) {
printf(", leftover = \"%s\"", leftover);
}
putchar('\n');
return 0;
}
在我的Linux系统上,我得到了正确的输出,即:
sprintf returned 20, buffer = "0x1.3333333333333p+0"
sscanf returned 1, x = 1.200000
在Cygwin下,我得到了以下输出:
sprintf returned 20, buffer = "0x1.3333333333333p+0"
sscanf returned 2, x = 0.000000, leftover = "x1.3333333333333p+0"
这段文字表明
"%lf"
格式导致
sscanf
只消耗了
0
,其余字符串将被
"%s"
消耗。这是C90实现的特点(在标准中添加
"%a"
之前)--但是
printf
的
"%a"
可以正确工作。
请在您的系统上尝试此操作。
更新7年后:我仍然在Windows 10下看到Cygwin存在相同问题。进一步的实验表明,它不支持
任何一个%a
格式说明符或十六进制浮点输入。在C99及更高版本中,
a
、
e
、
f
和
g
说明符的行为都相同,接受十进制或十六进制输入,因此,例如,
%la
格式应该接受像
1.0
这样的输入。我已向Cygwin邮件列表提交了错误报告:
https://cygwin.com/pipermail/cygwin/2021-April/248315.html
更新2:新的补丁已经推送到newlib-cygwin,可以修复此问题,并提供了新的开发者快照。如果一切顺利,我认为Cygwin将很快更新此修复程序。
https://cygwin.com/pipermail/cygwin/2021-April/248323.html
%a
并不是标准格式。根据man手册的建议,%a
不应该与l
一起使用。 - Crowman%a
可以在 C 2011 标准中找到。第7.21.6.1节,第8段。 - Bill Lynchsscanf
函数,而是由运行时库来实现。如果你使用的gcc安装使用了Microsoft库,它可能无法完全实现sscanf
函数;Microsoft倾向于不太好地支持C99及其后续版本。 - Keith Thompsonsscanf(buffer, "%la", &x);
的结果,例如if (sscanf(buffer, "%la", &x) != 1) HandleError();
。严谨的代码会执行int n; if (sscanf(buffer, "%la%n", &x, &n) != 1 || buffer[n]) HandleError();
。 - chux - Reinstate Monica