[英]sscanf multi string scan
我想用sscanf在c中捕獲以下字符串
"1=Salam Khobi|FC93F8A120F491F3A8=Rial|F191FEA4"
但是sscanf僅將&customInput.type
和customInputTitle[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()
將恢復與|
匹配|
字符。 下一條指令應為文字|
避免匹配失敗。 在原始代碼中,使用%[^|]s
, s
不屬於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.title
和customInput.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 -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.