我想用sscanf在c中捕获以下字符串
"1=Salam Khobi|FC93F8A120F491F3A8=Rial|F191FEA4"
但是sscanf仅用{Salam Khobi“填充&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;
}
答案 0 :(得分:1)
select hll_set_defaults(17,5,-1,1);
是正确的格式。
答案 1 :(得分:1)
在scanset伪指令|
遇到%[^|]
字符后,sscanf()
将恢复与|
字符的匹配。下一条指令应为文字|
,以避免匹配失败。在原始代码中,对于%[^|]s
,s
不是scanset指令的一部分,而是sscanf()
试图匹配文字{{1} }。另外,请注意,应始终将最大宽度说明符与s
和%s
%[]
系列指令一起使用,以避免由于恶意或格式错误的输入而导致缓冲区溢出:
fscanf()
在编译C代码时始终启用警告;这样做可以帮助您避免几个严重的问题。此代码有很多警告,并且下面列出的大多数问题都导致未定义的行为。我总是至少使用"%d=%39[^|]|%39[^=]=%39[^|]|%39s"
,并在答案的末尾添加了原始代码的gcc输出示例。
gcc -std=c11 -Wall -Wextra -Wpedantic
中缺少发布的代码#include <string.h>
。
memset()
的{{1}}和.title
字段应为.extra
,因为它们指向lcdInput
数组的首个元素。
在unsigned char *
的初始化中,unsigned char
运算符应被删除。 customInput
和&
都期望有指向customInput.title
(或在上述更正之前的customInput.extra
)的指针。与,例如unsigned char
有一个指向char
&customInputTitle[0]
s(或在上述更正之前的CUSTOM_INPUT_LENGTH
s)数组的指针;这是类型不匹配,您的编译器应大声抱怨(启用警告)。相反,只需使用:
unsigned char
在这里,char
是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]
数组中删除与号。在这里,您还需要对customInput
做一些事情。这是sscanf()
类型,您不能输入&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()
的值范围。如果输入符合预期,则将typeInput
分配给inputType
。
对typeInput
的调用将起作用,但是为什么用位移来混淆事物呢?您也不需要customInput.type
运算符,但是在这种情况下,它们可以。相反,请考虑:
memset()
这是更正的代码。使用&
编译时没有警告:
memset(customInputTitle, 0, sizeof customInputTitle);
memset(customInputExtra, 0, sizeof customInputExtra);
以下是问题中发布的原始程序中带有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;
}