簡體   English   中英

sscanf多字符串掃描

[英]sscanf multi string scan

我想用sscanf在c中捕獲以下字符串

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

但是sscanf僅將&customInput.typecustomInputTitle[0]填充為“ Salam Khobi”,而字符串的其他部分將不會掃描。

 #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;
}

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

問的問題

經過| 用scanset指令%[^|]遇到字符, sscanf()將恢復與|匹配| 字符。 下一條指令應為文字| 避免匹配失敗。 在原始代碼中,使用%[^|]ss 屬於scanset偽指令,而是sscanf()尋求與輸入中的文字s匹配。 另外,請注意,應始終將最大寬度說明符與%s%[] fscanf()系列指令一起使用,以避免由於惡意或格式錯誤的輸入而導致的緩沖區溢出:

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

其他一些嚴重問題

編譯C代碼時始終啟用警告; 這樣做可以幫助您避免幾個嚴重的問題。 此代碼有很多警告,並且下面列出的大多數問題都導致未定義的行為。 我總是至少使用gcc -std=c11 -Wall -Wextra -Wpedantic ,並且在答案的末尾添加了原始代碼的gcc輸出示例。

發布的代碼缺少memset() #include <string.h>

.title.extra領域lcdInput應該是unsigned char * ,因為這些點的第一元件unsigned char陣列。

customInput的初始化中,應刪除&運算符。 customInput.titlecustomInput.extra都期望指向unsigned char (或在上述更正之前的char的指針。 用例如&customInputTitle[0]你有一個指針指向的數組CUSTOM_INPUT_LENGTH unsigned char S(或char S上的上述校正前); 這是類型不匹配,您的編譯器應大聲抱怨(啟用警告)。 相反,只需使用:

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

在這里, customInputTitle[0]CUSTOM_INPUT_LENGTH unsigned char數組,它將衰減為指向其第一個元素的指針( unsigned char * )。 另外,您可以使用&customInputTitle[0][0]&customInputTitle[1][0]等。

同樣,您需要在sscanf()的調用中從customInput數組中刪除“&” customInput 在這里,您還需要對&customInput.type做一些事情。 這是enum類型,您不能輸入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用於收集輸入,檢查sscanf()返回的值以驗證是否分配了正確的值,並對照inputType的值范圍檢查typeInput的值。 如果輸入符合預期, typeInput分配給customInput.type

memset()的調用將起作用,但是為什么用位移來混淆事物呢? 您也不需要在這里使用&運算符,但是在這種情況下,它們是可以的。 相反,請考慮:

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

這是更正的代碼。 使用gcc -std=c11 -Wall -Wextra -Wpedantic在沒有警告的情況下進行gcc -std=c11 -Wall -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 -std=c11 -Wall -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,
                     ^~~~~~~~~~~~~~~~~

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM