sscanf_s不返回字符串的第一个字符 [英] sscanf_s doesn't return first character of string

查看:95
本文介绍了sscanf_s不返回字符串的第一个字符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在C字符数组内以逗号分隔的字符串列表中找到第一个字符串(最多4个字符).

I'm trying to find the first string (max 4 characters) in a comma-separated list of strings inside a C char-array.

我正在尝试使用 sscanf_s (在Windows下)和格式控制字符串%[^,] :

I'm trying to achieve this by using sscanf_s (under Windows) and the format-control string %[^,]:

char mystring[] = "STR1,STR2";
char temp[5];

if (sscanf_s(mystring, "%[^,]", temp, 5) != 0) {
    if (strcmp(temp, "STR1") == 0) { return 0; }
    else if (strcmp(temp, "STR2") == 0) { return 1; }
    else { return -1; }
}

在调用 sscanf_s 后,temp的内容不是 STR1 ,而是 \ 0TR1 ( \ 0 是ASCII- 0 的解释).并返回值 -1 .

After calling sscanf_s the content of temp is not STR1 but \0TR1 (\0 being the ASCII-interpretation of 0). And the value -1 is returned.

为什么会出现这种行为,以及如何修复代码以获得正确的结果(返回 0 )?

Why do I get that behavior and how do I fix my code to get the right result (return of 0)?

将char mystring 更改为 mystring [] (我应该确保我在此处正确键入了内容)

changed char mystring to mystring[] (I should have made sure I typed it correcly here)

推荐答案

您的代码中存在多个问题:

There are multiple problems in your code:

  • mystring 被定义为 char ,而不是字符串指针.
  • sscanf_s()中的 temp 之后的参数 5 应该具有 rsize_t 类型,该类型与 size_t .您应将其指定为 sizeof(temp).
  • 您应该在格式字符串中指定要存储到目标数组中的最大字符数,以避免在溢出的情况下 sscanf_s 违反直觉的行为.
  • sscanf_s 如果可以转换和存储字符串,则返回 1 .测试!= 0 还将接受 EOF ,这是输入失败,因此 temp 的内容不确定.
  • mystring is defined as a char, not a string pointer.
  • the argument 5 following temp in sscanf_s() should have type rsize_t, which is the same as size_t. You should specify it as sizeof(temp).
  • you should specify the maximum number of characters to store into the destination array in the format string, to avoid the counter-intuitive behavior of sscanf_s in case of overflow.
  • sscanf_s returns 1 if it can convert and store the string. Testing != 0 will also accept EOF which is an input failure, for which the contents of temp is indeterminate.

这是修改后的版本:

const char *mystring = "STR1,STR2";
char temp[5];

if (sscanf_s(mystring, "%4[^,]", temp, sizeof temp) == 1) {
    if (strcmp(temp, "STR1") == 0) {
        return 0;
    } else
    if (strcmp(temp, "STR2") == 0) {
        return 1; 
    } else {
        return -1;
    }
}

更新:OP使用Microsoft Visual Studio,它似乎对所谓的 secure 流函数具有不一致的实现.这是他们的

UPDATE: The OP uses Microsoft Visual Studio, which seems to have a non-conforming implemtation of the so-called secure stream functions. Here is an citation from their documentation page:

sscanf_s 函数将数据从缓冲区读入每个参数指定的位置.格式字符串后面的参数指定指向类型与格式中的类型说明符相对应的变量的指针.与不太安全的版本 sscanf 不同,当您使用类型字段字符 c C s S 或包含在 [] 中的字符串控件集.缓冲区大小(以字符为单位)必须在每个需要它的缓冲区参数之后立即作为附加参数提供.例如,如果您正在读取一个字符串,则该字符串的缓冲区大小将按以下方式传递:

The sscanf_s function reads data from buffer into the location that's given by each argument. The arguments after the format string specify pointers to variables that have a type that corresponds to a type specifier in format. Unlike the less secure version sscanf, a buffer size parameter is required when you use the type field characters c, C, s, S, or string control sets that are enclosed in []. The buffer size in characters must be supplied as an additional parameter immediately after each buffer parameter that requires it. For example, if you are reading into a string, the buffer size for that string is passed as follows:

wchar_t ws[10];
swscanf_s(in_str, L"%9s", ws, (unsigned)_countof(ws)); // buffer size is 10, width specification is 9

缓冲区大小包括终止null.宽度规范字段可用于确保读入的令牌将适合缓冲区.如果未使用宽度指定字段,并且读入的令牌太大而无法容纳在缓冲区中,则不会向该缓冲区写入任何内容.

The buffer size includes the terminating null. A width specification field may be used to ensure that the token that's read in will fit into the buffer. If no width specification field is used, and the token read in is too big to fit in the buffer, nothing is written to that buffer.

对于字符,单个字符可以如下读取:

In the case of characters, a single character may be read as follows:

wchar_t wc;
swscanf_s(in_str, L"%c", &wc, 1);

此示例从输入字符串中读取单个字符,然后将其存储在宽字符缓冲区中.当您读取非空终止字符串的多个字符时,会将无符号整数用作宽度说明和缓冲区大小.

This example reads a single character from the input string and then stores it in a wide-character buffer. When you read multiple characters for non-null terminated strings, unsigned integers are used as the width specification and the buffer size.

char c[4];
sscanf_s(input, "%4c", &c, (unsigned)_countof(c)); // not null terminated

此示例从输入字符串中读取单个字符,然后将其存储在宽字符缓冲区中.当您读取非空终止字符串的多个字符时,会将无符号整数用作宽度说明和缓冲区大小.

This example reads a single character from the input string and then stores it in a wide-character buffer. When you read multiple characters for non-null terminated strings, unsigned integers are used as the width specification and the buffer size.

char c[4];
sscanf_s(input, "%4c", &c, (unsigned)_countof(c)); // not null terminated

此规范与C标准不兼容,该标准将width参数的类型指定为 rsize_t ,并将类型 rsize_t 设置为与 size_t相同的类型..

This specification is incompatible with the C Standard, that specifies the type of the width arguments to be rsize_t and type rsize_t to be the same type as size_t.

结论是,为了提高可移植性,应该避免使用这些 secure 函数并正确使用标准函数,并使用长度前缀来防止缓冲区溢出.

As a conclusion, for improved portability, one should avoid using these secure functions and use the standard functions correctly, with the length prefix to prevent buffer overruns.

这篇关于sscanf_s不返回字符串的第一个字符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆