微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

C++ sscanf 接缝无法按预期工作

如何解决C++ sscanf 接缝无法按预期工作

我目前正在使用 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",&registerIndex,&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:为了更好地理解草图的复杂性,这可能有助于更好地理解代码

  1. .ino 文件中的循环调用静态 Commander::process()。
  2. 指挥官::_readLine(...);被调用并从串行读取数据。
  3. 完成了更多验证,但在这种情况下应该无关紧要
  4. Commander::parseCommand(command);使用命令调用
  5. registers->setThrottle(command);当命令以“t”开头时被调用。 registers 是不稳定的,所以我可以从中断中调用它。
  6. 在 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;
}

数量有限但体积小,对我来说已经足够了。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。