在将sscanf()用于STM32F437的过程中,我遇到了一些有趣的事情:
uint8_t var;
st = sscanf(&line[off], "%x", &var);
st = sscanf(&line[off], "%hhx", &var);
当我尝试编译第一行时,我收到gcc的建议,建议使用“%hhx”而不是“%x”。但是,当我将此行更改为第二行时-来自gcc的建议消失了,但是扫描的结果是错误的。
当&line [off]指向以下字符串:52时,第一个scanf(...“%x” ...)正常工作,给出0x52,但是第二个scanf(...“%hhx”。) 。)产生结果0x34。
似乎scanf(“ ...”%hhx“ ...”)将52解释为十进制值52,然后将其转换为十六进制值0x34。 我正在使用arm-none-eabi-gcc版本9.2.0。
我错过了什么吗,或者这是scanf()中的错误吗?
答案 0 :(得分:2)
%x
在x
之前没有前缀,表示scanf期望指向unsigned int
的指针%hh
用于signed char
或unsigned char
。%hhx
用于十六进制格式的signed char
或unsigned char
。"%"SCNu8
用于扫描uint8_t
。"%"SCNx8
用于十六进制格式的uint8_t
。uint8_t
在任何系统上很可能100%等同于unsigned char
。这意味着"%x", &var
在这里,您对编译器撒谎,并且(假设32位CPU)告诉它“继续并读取32位大整数),然后传递仅8位有效数据的内存地址存储。这是未定义的行为,任何事情都可能发生。
猜测为什么未定义的行为错误会以特定的方式出现在您的特定系统中,这毫无意义。
相反,请执行以下操作:
#include <inttypes.h>
uint8_t var;
st = sscanf(&line[off], "%"SCNx8, &var);
请注意,sscanf
是一个非常缓慢和危险的功能,不应在嵌入式系统上使用。始终改为使用strtoul
。
答案 1 :(得分:1)
您正在链接通常称为“ newlib-nano”的链接。 Nanolib的newlib版本从标准库中获得了有限的支持-它不支持ll
和hh
和printf
中的所有C99 length修饰符 scanf
。
解决方案是链接到newlib的完整实现,因此从链接选项中删除-specs=nano.specs
或类似内容,或者在编译时不要使用hh
length修饰符 newlib-nano或使用其他方法将字符串转换为整数。