代码之家  ›  专栏  ›  技术社区  ›  knittl

sscanf将多个格式说明符转换为单个数组

  •  1
  • knittl  · 技术社区  · 3 年前

    可以跑步吗 sscanf 具有多个格式说明符,每个格式说明符将在数组中设置一个项目?目前,我必须分别指定指向每个数组槽的指针,这感觉非常重复:

    unsigned int buffer[8];
    sscanf(
            line,
            "%6o %6o %6o %6o %6o %6o %6o %6o",
            buffer + 0,
            buffer + 1,
            buffer + 2,
            buffer + 3,
            buffer + 4,
            buffer + 5,
            buffer + 6,
            buffer + 7);
    

    我正在寻找类似JavaScript的东西 spread operator 或Python的 * -operator for unpacking argument lists :

    sscanf(
            line,
            "%6o %6o %6o %6o %6o %6o %6o %6o",
            ...buffer);
    

    目前,此操作失败,并出现以下错误:

    文件.c:42:21:错误:format%o需要一个匹配的无符号int*参数[-Weror=format=]

    这是意料之中的事。我该怎么说 sscanf 将每个格式说明符值放入数组中的连续槽中?有可能吗?如果没有,有没有聪明的变通方法(破解)?

    1 回复  |  直到 3 年前
        1
  •  2
  •   chux    3 年前

    如何告诉sscanf将每个格式说明符值放入数组中的连续槽中?有可能吗?如果没有,有没有聪明的变通方法(破解)?

    使用循环。

    稳健代码还可以检测是否 line 不包含8组八进制数字文本。


    的替代方案 strtol() 循环是 sscanf() 具有 "%6o %n"

    " %n" 扫描可选的空白空间,然后保存扫描的偏移量。

    size_t n = sizeof buffer / sizeof buffer[0];  // 8
    
    const char *p = line;
    size_t i;
    for (i = 0; i < n; i++) {
      int n = 0;
      if (sscanf(p, "%6o %n", &buffer[i], &n) != 1) {  // or use strtol()
        Handle_scanf_failure(); // Add user code here to cope with this error
      }
      p += n; // Advance p to the next part of the buffer
    }
    if (*p != '\0') {
      Handle_junk_at_end_of_buffer(); // Add user code here to cope with this error
    }
    

    strtol() 更好地处理溢出 "%o" ,但由于我们有一个最大值 宽度 由6个八进制数字组成,可防止32位溢出 unsigned

        2
  •  2
  •   Ted Lyngmo    3 年前

    我该怎么说 sscanf 将每个格式说明符值放入数组中的连续槽中?有可能吗?

    根据 scanf 没有这样的转换说明符。

    如果没有,有没有聪明的变通方法(破解)?

    是的,循环并一次提取一个。 strtoul 在这种情况下可能是有用的。

    示例:

    #include <errno.h>
    #include <limits.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    size_t scan_uint_array(const char *line, unsigned int buffer[], size_t count, int base)
    {
        char *str_end;
        for(size_t i = 0; i < count; ++i) {
            unsigned long tmp = strtoul(line, &str_end, base);
            if(str_end == line) return i; // no conversion done
            if(errno == ERANGE) return i; // out of range for ULONG
            if(tmp > UINT_MAX) {          // out of range for UINT
                errno = ERANGE;
                return i;
            }
            buffer[i] = tmp; // all good, save this
            line = str_end;  // move line to where the next scan should be done
        }
        return count;
    }
    
    #define Size(x) (sizeof (x) / sizeof *(x))
    
    int main() {
        unsigned int buffer[8];
        size_t ex = scan_uint_array(" 1 2 3 4 5 6 7 ", buffer, Size(buffer), 8);
        
        printf("extracted=%zu wanted=%zu\n", ex, Size(buffer));
        
        for(size_t i = 0; i < ex; ++i)
            printf("%u ", buffer[i]);
    }
    

    输出

    extracted=7 wanted=8
    1 2 3 4 5 6 7