问题描述
我目前正在使用 Arduino Uno 为学校开展项目,但遇到了 C sscanf 函数的问题。下面的代码正在解析通过串行接口发送到 Arduino 的字符数组。每个数据块用空格分隔。我也在 Stackoverflow 上检查了类似的问题,但没有发现任何帮助。
char testInput[] = "t 1 3 65 1";
int registerIndex;
int locoAddr;
int locoSpeed;
int locoDirection;
if(sscanf(testInput,"t %d %d %d %d",®isterIndex,&locoAddr,&locoSpeed,&locoDirection) != 4) {
return;
}
// print for demo:
Serial.print(registerIndex);
Serial.print(": ");
Serial.print("loco:");
Serial.print(locoAddr);
Serial.print(" speed:");
Serial.print(locoSpeed);
Serial.print(" direction:");
Serial.println(locoDirection);
// expected output: "1: loco:3 speed:65 direction:1"
// output: "-18248: loco:-18248 speed:-18248 direction:-18248"
sscanf 函数返回预期的整数 4,但没有用值填充变量,因此只打印默认值。
我不知道问题可能是什么。也许互联网上有人有解决方案。
编辑 1:为了更好地理解草图的复杂性,这可能有助于更好地理解代码:
- .ino 文件中的循环调用静态 Commander::process()。
- 指挥官::_readLine(...);被调用并从串行读取数据。
- 完成了更多验证,但在这种情况下应该无关紧要
- Commander::parseCommand(command);使用命令调用。
- registers->setThrottle(command);当命令以“t”开头时被调用。 registers 是不稳定的,所以我可以从中断中调用它。
- 在 PackageRegisterList::setThrottle 中是 sscanf 方法。
解决方法
我通常使用从 Linux 内核中窃取的这个版本:
int ASCII_vsscanf(const char * buf,const char * fmt,va_list args)
{
const char *str = buf;
char *next;
char digit;
int num = 0;
int qualifier;
int base;
int field_width;
int is_sign = 0;
while(*fmt && *str) {
/* skip any white space in format */
/* white space in format matchs any amount of
* white space,including none,in the input.
*/
if (isspace(*fmt)) {
while (isspace(*fmt))
++fmt;
while (isspace(*str))
++str;
}
/* anything that is not a conversion must match exactly */
if (*fmt != '%' && *fmt) {
if (*fmt++ != *str++)
break;
continue;
}
if (!*fmt)
break;
++fmt;
/* skip this conversion.
* advance both strings to next white space
*/
if (*fmt == '*') {
while (!isspace(*fmt) && *fmt)
fmt++;
while (!isspace(*str) && *str)
str++;
continue;
}
/* get field width */
field_width = -1;
if (isdigit(*fmt))
field_width = skip_atoi(&fmt);
/* get conversion qualifier */
qualifier = -1;
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
*fmt == 'Z' || *fmt == 'z') {
qualifier = *fmt++;
if (unlikely(qualifier == *fmt)) {
if (qualifier == 'h') {
qualifier = 'H';
fmt++;
} else if (qualifier == 'l') {
qualifier = 'L';
fmt++;
}
}
}
base = 10;
is_sign = 0;
if (!*fmt || !*str)
break;
switch(*fmt++) {
case 'c':
{
char *s = (char *) va_arg(args,char*);
if (field_width == -1)
field_width = 1;
do {
*s++ = *str++;
} while (--field_width > 0 && *str);
num++;
}
continue;
case 's':
{
char *s = (char *) va_arg(args,char *);
if(field_width == -1)
field_width = INT_MAX;
/* first,skip leading white space in buffer */
while (isspace(*str))
str++;
/* now copy until next white space */
while (*str && !isspace(*str) && field_width--) {
*s++ = *str++;
}
*s = '\0';
num++;
}
continue;
case 'n':
/* return number of characters read so far */
{
int *i = (int *)va_arg(args,int*);
*i = str - buf;
}
continue;
case 'o':
base = 8;
break;
case 'x':
case 'X':
base = 16;
break;
case 'i':
base = 0;
case 'd':
is_sign = 1;
case 'u':
break;
case '%':
/* looking for '%' in str */
if (*str++ != '%')
return num;
continue;
default:
/* invalid format; stop here */
return num;
}
/* have some sort of integer conversion.
* first,skip white space in buffer.
*/
while (isspace(*str))
str++;
digit = *str;
if (is_sign && digit == '-')
digit = *(str + 1);
if (!digit
|| (base == 16 && !isxdigit(digit))
|| (base == 10 && !isdigit(digit))
|| (base == 8 && (!isdigit(digit) || digit > '7'))
|| (base == 0 && !isdigit(digit)))
break;
switch(qualifier) {
case 'H': /* that's 'hh' in format */
if (is_sign) {
signed char *s = (signed char *) va_arg(args,signed char *);
*s = (signed char) ASCII_simple_strtol(str,&next,base);
} else {
unsigned char *s = (unsigned char *) va_arg(args,unsigned char *);
*s = (unsigned char) ASCII_simple_strtoul(str,base);
}
break;
case 'h':
if (is_sign) {
short *s = (short *) va_arg(args,short *);
*s = (short) ASCII_simple_strtol(str,base);
} else {
unsigned short *s = (unsigned short *) va_arg(args,unsigned short *);
*s = (unsigned short) ASCII_simple_strtoul(str,base);
}
break;
case 'l':
if (is_sign) {
long *l = (long *) va_arg(args,long *);
*l = ASCII_simple_strtol(str,base);
} else {
unsigned long *l = (unsigned long*) va_arg(args,unsigned long*);
*l = ASCII_simple_strtoul(str,base);
}
break;
case 'L':
if (is_sign) {
long long *l = (long long*) va_arg(args,long long *);
*l = ASCII_simple_strtoll(str,base);
} else {
unsigned long long *l = (unsigned long long*) va_arg(args,unsigned long long*);
*l = ASCII_simple_strtoull(str,base);
}
break;
case 'Z':
case 'z':
{
size_t *s = (size_t*) va_arg(args,size_t*);
*s = (size_t) ASCII_simple_strtoul(str,base);
}
break;
default:
if (is_sign) {
int *i = (int *) va_arg(args,int*);
*i = (int) ASCII_simple_strtol(str,base);
} else {
unsigned int *i = (unsigned int*) va_arg(args,unsigned int*);
*i = (unsigned int) ASCII_simple_strtoul(str,base);
}
break;
}
num++;
if (!next)
break;
str = next;
}
return num;
}
数量有限但体积小,对我来说已经足够了。