分享
三行代码  ›  专栏  ›  技术社区  ›  COP

多串扫描

  •  0
  • COP  · 技术社区  · 10 月前

    我想用scsanf捕获下面的C字符串

    "1=Salam Khobi|FC93F8A120F491F3A8=Rial|F191FEA4"
    

    但SScanf只填 &customInput.type customInputTitle[0] 与“萨拉姆河”和其他部分的字符串不会扫描。

     #include <stdio.h>
    #include <stdlib.h>
    
    typedef enum {
        INPUT_NUMBER = 0,
        INPUT_NORMAL = 1,
        INPUT_PASSWORD = 2,
        INPUT_PAYAMOUNT = 3,
    } inputType;
    
    typedef struct {
        char * title[2];
        char * extra[2];
        inputType type;
        unsigned minLen:6;
        unsigned maxLen:6;
        unsigned forceLen:1;
        unsigned editable:1;
        unsigned char data[100];
    } lcdInput;
    #define CUSTOM_INPUT_LENGTH     40
    static unsigned char customInputTitle[2][CUSTOM_INPUT_LENGTH];
    static unsigned char customInputExtra[2][CUSTOM_INPUT_LENGTH];
    const char * payload = "1=Salam Khobi|FC93F8A120F491F3A8=Rial|F191FEA4";
    #define CUSTOM_INPUT_REGX       "%d=%[^|]s|%[^=]s=%[^|]s|%s"
    static lcdInput customInput = {
            .title = {&customInputTitle[0], &customInputTitle[1]},
            .extra = {&customInputExtra[0], &customInputExtra[1]},
            .type = INPUT_NORMAL,
            .editable = 1,
            .forceLen = 0,
    };
    
    int main()
    {
        memset(&customInputTitle, 0, CUSTOM_INPUT_LENGTH << 1);
        memset(&customInputExtra, 0, CUSTOM_INPUT_LENGTH << 1);
    
        sscanf(payload, CUSTOM_INPUT_REGX,
               &customInput.type,
               &customInputTitle[0], &customInputTitle[1],
               &customInputExtra[0], &customInputExtra[1]);
    
        return 0;
    }
    
    2 回复  |  直到 10 月前
        1
  •  1
  •   COP    10 月前

    "%d=%[^|]|%[^=]=%[^|]|%s" 是正确的格式。

        2
  •  1
  •   David Bowling    10 月前

    问题是关于

    后一 | scanset指令遇到字符 %[^|] , sscanf() 将继续与匹配 γ 性格。下一个指令应为文本 γ 以避免匹配失败。在原始代码中, %[^|]s , the s scanset指令的一部分,而不是 sSCAN() 查找匹配文字 S 在输入中。另外,请注意,最大宽度说明符应始终与 %s %[] fscanf() 用于避免带有恶意或格式错误输入的缓冲区溢出的系列指令:

    "%d=%39[^|]|%39[^=]=%39[^|]|%39s"
    

    其他一些严重问题

    编译C代码时始终启用警告;在这里这样做可以帮助您避免几个严重的问题。此代码有很多警告,下面列出的大多数问题都会导致未定义的行为。我总是至少用 gcc -std=c11 -Wall -Wextra -Wpedantic 我在答案的末尾添加了一个用于原始代码的gcc输出示例。

    缺少已发布的代码 #include <string.h> 对于 memset() .

    这个 .title .extra 领域 lcdInput 应该是 unsigned char * ,因为这些指向 unsigned char 数组。

    在初始化时 customInput 这个 & 应移除操作员。 customInput.title customInput.extra 两者都需要指向 无符号字符 (或 char 在上述修正之前)。用,例如 &customInputTitle[0] 您有一个指向数组的指针 CUSTOM_INPUT_LENGTH 无符号字符 S(或) 烧焦 在进行上述更正之前);这是一个类型不匹配,编译器应该大声抱怨(启用警告)。相反,只需使用:

    static lcdInput customInput = {
        .title = {customInputTitle[0], customInputTitle[1]},
        .extra = {customInputExtra[0], customInputExtra[1]},
        .type = INPUT_NORMAL,
        .editable = 1,
        .forceLen = 0,
    };
    

    在这里, customInputTitle[0] 是一个数组 自定义输入长度 无符号字符 s,它将衰减为指向其第一个元素的指针( 无符号字符 )或者,您可以使用 &customInputTitle[0][0] ,请 &customInputTitle[1][0] 等。

    同样,您需要从 定制输入 调用中的数组 sSCAN() . 在这里你还需要做些什么 &customInput.type .这是一个 enum 类型,并且不能输入 枚举 价值。编译器再次抱怨启用了警告。相反,尝试:

    int typeInput;
    if (sscanf(payload, CUSTOM_INPUT_REGX,
               &typeInput,
               customInputTitle[0], customInputTitle[1],
               customInputExtra[0], customInputExtra[1]) == 5) {
        if (typeInput >= INPUT_NUMBER && typeInput <= INPUT_PAYAMOUNT) {
            customInput.type = typeInput;
        } else {
            /* Handle error */
        }
    };
    

    在这里 typeInput 用于收集输入,返回的值 sSCAN() 检查以验证分配的值数量是否正确,以及 输入类型 根据的值范围检查 inputType . 如果输入如预期, 输入类型 分配给 customInput.type .

    呼唤 MeMSET() 会有用的,但是为什么要用位移混淆事物呢?你不需要 & 这里的操作员也可以,但在这种情况下他们可以。相反,考虑:

    memset(customInputTitle, 0, sizeof customInputTitle);
    memset(customInputExtra, 0, sizeof customInputExtra);
    

    这是正确的代码。编译时没有警告,使用 GCC-标准=C11-墙-Wextra-wpedantic :

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>        // missing header
    
    typedef enum {
        INPUT_NUMBER = 0,
        INPUT_NORMAL = 1,
        INPUT_PASSWORD = 2,
        INPUT_PAYAMOUNT = 3,
    } inputType;
    
    typedef struct {
        unsigned char * title[2];    // need unsigned char
        unsigned char * extra[2];
        inputType type;
        unsigned minLen:6;
        unsigned maxLen:6;
        unsigned forceLen:1;
        unsigned editable:1;
        unsigned char data[100];
    } lcdInput;
    
    #define CUSTOM_INPUT_LENGTH     40
    
    static unsigned char customInputTitle[2][CUSTOM_INPUT_LENGTH];
    static unsigned char customInputExtra[2][CUSTOM_INPUT_LENGTH];
    const char * payload = "1=Salam Khobi|FC93F8A120F491F3A8=Rial|F191FEA4";
    
    // bad format string
    #define CUSTOM_INPUT_REGX       "%d=%39[^|]|%39[^=]=%39[^|]|%39s"
    
    // & operator not needed
    static lcdInput customInput = {
        .title = {customInputTitle[0], customInputTitle[1]},
        .extra = {customInputExtra[0], customInputExtra[1]},
        .type = INPUT_NORMAL,
        .editable = 1,
        .forceLen = 0,
    };
    
    int main(void)
    {
        // could use improvements
        memset(customInputTitle, 0, sizeof customInputTitle);
        memset(customInputExtra, 0, sizeof customInputExtra);
    
        // & operators not needed
        int typeInput;
        if (sscanf(payload, CUSTOM_INPUT_REGX,
                   &typeInput,
                   customInputTitle[0], customInputTitle[1],
                   customInputExtra[0], customInputExtra[1]) == 5) {
            if (typeInput >= INPUT_NUMBER && typeInput <= INPUT_PAYAMOUNT) {
                customInput.type = typeInput;
            } else {
                /* Handle error */
            }
        };
    
        return 0;
    }
    

    带警告的GCC输出

    以下是编译器警告 GCC-标准=C11-墙-Wextra-wpedantic 从问题中发布的原始程序:

    bad_program.c:27:19: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
             .title = {&customInputTitle[0], &customInputTitle[1]},
                       ^
    bad_program.c:27:19: note: (near initialization for ‘customInput.title[0]’)
    bad_program.c:27:41: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
             .title = {&customInputTitle[0], &customInputTitle[1]},
                                             ^
    bad_program.c:27:41: note: (near initialization for ‘customInput.title[1]’)
    bad_program.c:28:19: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
             .extra = {&customInputExtra[0], &customInputExtra[1]},
                       ^
    bad_program.c:28:19: note: (near initialization for ‘customInput.extra[0]’)
    bad_program.c:28:41: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
             .extra = {&customInputExtra[0], &customInputExtra[1]},
                                             ^
    bad_program.c:28:41: note: (near initialization for ‘customInput.extra[1]’)
    bad_program.c: In function ‘main’:
    bad_program.c:36:5: warning: implicit declaration of function ‘memset’ [-Wimplicit-function-declaration]
         memset(&customInputTitle, 0, CUSTOM_INPUT_LENGTH << 1);
         ^~~~~~
    bad_program.c:36:5: warning: incompatible implicit declaration of built-in function ‘memset’
    bad_program.c:36:5: note: include ‘<string.h>’ or provide a declaration of ‘memset’
    bad_program.c:25:33: warning: format ‘%d’ expects argument of type ‘int *’, but argument 3 has type ‘inputType * {aka enum <anonymous> *}’ [-Wformat=]
     #define CUSTOM_INPUT_REGX       "%d=%[^|]s|%[^=]s=%[^|]s|%s"
                                     ^
    bad_program.c:39:21: note: in expansion of macro ‘CUSTOM_INPUT_REGX’
         sscanf(payload, CUSTOM_INPUT_REGX,
                         ^~~~~~~~~~~~~~~~~
    bad_program.c:25:33: warning: format ‘%[^|’ expects argument of type ‘char *’, but argument 4 has type ‘unsigned char (*)[40]’ [-Wformat=]
     #define CUSTOM_INPUT_REGX       "%d=%[^|]s|%[^=]s=%[^|]s|%s"
                                     ^
    bad_program.c:39:21: note: in expansion of macro ‘CUSTOM_INPUT_REGX’
         sscanf(payload, CUSTOM_INPUT_REGX,
                         ^~~~~~~~~~~~~~~~~
    bad_program.c:25:33: warning: format ‘%[^=’ expects argument of type ‘char *’, but argument 5 has type ‘unsigned char (*)[40]’ [-Wformat=]
     #define CUSTOM_INPUT_REGX       "%d=%[^|]s|%[^=]s=%[^|]s|%s"
                                     ^
    bad_program.c:39:21: note: in expansion of macro ‘CUSTOM_INPUT_REGX’
         sscanf(payload, CUSTOM_INPUT_REGX,
                         ^~~~~~~~~~~~~~~~~
    bad_program.c:25:33: warning: format ‘%[^|’ expects argument of type ‘char *’, but argument 6 has type ‘unsigned char (*)[40]’ [-Wformat=]
     #define CUSTOM_INPUT_REGX       "%d=%[^|]s|%[^=]s=%[^|]s|%s"
                                     ^
    bad_program.c:39:21: note: in expansion of macro ‘CUSTOM_INPUT_REGX’
         sscanf(payload, CUSTOM_INPUT_REGX,
                         ^~~~~~~~~~~~~~~~~
    bad_program.c:25:33: warning: format ‘%s’ expects argument of type ‘char *’, but argument 7 has type ‘unsigned char (*)[40]’ [-Wformat=]
     #define CUSTOM_INPUT_REGX       "%d=%[^|]s|%[^=]s=%[^|]s|%s"
                                     ^
    bad_program.c:39:21: note: in expansion of macro ‘CUSTOM_INPUT_REGX’
         sscanf(payload, CUSTOM_INPUT_REGX,
                         ^~~~~~~~~~~~~~~~~