我想用sscanf捕获以下c#中的字符串
"1=Salam Khobi|FC93F8A120F491F3A8=Rial|F191FEA4"但是scan只使用"Salam“填充&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;
}发布于 2018-12-19 12:04:46
"%d=%[^|]|%[^=]=%[^|]|%s"是正确的格式。
发布于 2018-12-19 13:59:57
问题被问到了
当一个|字符被扫描集指令%[^|]遇到后,sscanf()将恢复与|字符的匹配。下一个指令应该是一个文字|,以避免匹配失败。在原始代码中,使用%[^|]s时,s不是扫描集指令的一部分,相反,sscanf()试图在输入中匹配一个文字s。另外,请注意,应始终在%s和%[] fscanf()系列指令中使用最大宽度说明符,以避免恶意或格式错误输入的缓冲区溢出:
"%d=%39[^|]|%39[^=]=%39[^|]|%39s"其他一些严重问题
在编译C代码时始终启用警告;这样做可以帮助您避免几个严重的问题。对于这段代码有很多警告,下面列出的大多数问题都会导致未定义的行为。我总是至少使用gcc -std=c11 -Wall -Wextra -Wpedantic,并且在答案的末尾为原始代码添加了gcc输出的示例。
发布的代码缺少#include <string.h> for memset()。
.title和.extra字段的lcdInput应该是unsigned char *,因为它们指向unsigned char数组的第一个元素。
在customInput的初始化过程中,应该删除&操作符。customInput.title和customInput.extra都期望指向unsigned char (或在上述更正之前的chars )的指针。例如,对于&customInputTitle[0],您有一个指向CUSTOM_INPUT_LENGTH unsigned chars数组的指针(或在上面更正之前的chars );这是类型不匹配,编译器应该发出响亮的抱怨(启用了警告)。相反,只需使用:
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()返回的值以验证是否分配了正确的值,并根据inputType的值范围检查typeInput的值。如果输入与预期的相同,则将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;
}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,
^~~~~~~~~~~~~~~~~https://stackoverflow.com/questions/53850625
复制相似问题