允许 NULL arg 进行 sscanf?

发布于 2024-10-20 02:29:53 字数 326 浏览 2 评论 0原文

是否允许使用 NULL 指针作为调用 sscanf 时存储结果的字符串?

我在任何文档中都没有找到任何有关它的信息,但它似乎工作正常。 scanf 也是如此。

示例:

int main(int arc, char* argv[])
{
  char* s = NULL;
  sscanf("Privjet mir!", "%s", s);
  printf("s: %s\n", s);
  return 0;
}

输出:s: (null)

Is a NULL pointer allowed as the string to store result in in a call to sscanf?

I don't find anything about it in any documentation but it seems to be working fine. Same thing with scanf.

Example:

int main(int arc, char* argv[])
{
  char* s = NULL;
  sscanf("Privjet mir!", "%s", s);
  printf("s: %s\n", s);
  return 0;
}

Output: s: (null)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

冷弦 2024-10-27 02:29:53

不:

匹配非空白序列
人物;下一个指针必须是
指向字符数组的指针
足够长的时间来保存输入序列
和终止空字符
('\0'),这是自动添加的。
输入字符串在空格处停止
或在最大字段宽度时,
以先发生者为准。

(http://linux.die.net/man/3/sscanf)

No:

Matches a sequence of non-white-space
characters; the next pointer must be a
pointer to character array that is
long enough to hold the input sequence
and the terminating null character
('\0'), which is added automatically.
The input string stops at white space
or at the maximum field width,
whichever occurs first.

(http://linux.die.net/man/3/sscanf)

凉薄对峙 2024-10-27 02:29:53

正如其他答案所提到的,NULL 不能作为附加参数传递给 sscanf

http://www.cplusplus.com/reference/cstdio/sscanf 说附加论点:

根据格式字符串,该函数可能需要一系列附加参数,每个参数都包含一个指向已分配存储空间的指针,其中提取的字符的解释以适当的类型存储

对于 %s 说明符,这些提取的字符是

任意数量的非空白字符,在找到的第一个空白字符处停止。终止空字符会自动添加到存储序列的末尾。

所以当存储“非空白字符”和“终止空字符”时,就会出现段错误。这正是 Visual Studio 将产生的结果(您可以在 http://webcompiler.cloudapp.net/< 处测试这是否失败/a>):

在此处输入图像描述

现在,对于非 Visual Studio 编译器,libc 的 %s 说明符的提取代码: com/ffainelli/uClibc/blob/master/libc/stdio/_scanf.c#L1376" rel="nofollow noreferrer">https://github.com/ffainelli/uClibc/blob/master/libc/stdio/_scanf.c #L1376 具有主要注释:/* 我们可能必须自己处理分配 */ 这是因为:

GNU C 库通过 a 字符支持动态分配转换说明符(作为非标准扩展)。这个功能似乎至少早在 glibc 2.0 就已经存在。
从 2.7 版开始,glibc 还提供了 m 修饰符,其用途与 a 修饰符相同。

[来源]

因此,因为 libc 提取到内部构造为 sscanf< 的缓冲区/code> 并随后检查缓冲区参数在分配之前是否没有设置标志,它永远不会将字符写入 NULL 缓冲区参数。

我必须强调这是非标准的,并且即使在次要的库更新之间也不能保证被保留。更好的方法是使用 * 子说明符:

表示数据将从流中读取但被忽略(即它不存储在参数指向的位置)。

[来源]

这可以像这样完成,例如:

s == NULL ? sscanf("Privjet mir!", "%*s") : sscanf("Privjet mir!", "%s", s);

显然是真实的三元的 -branch 是一个无操作,但我将其包含在内,期望从字符串中读取其他数据。

As is mentioned by the other answers NULL is not valid to pass to sscanf as an additional argument.

http://www.cplusplus.com/reference/cstdio/sscanf says of additional arguments:

Depending on the format string, the function may expect a sequence of additional arguments, each containing a pointer to allocated storage where the interpretation of the extracted characters is stored with the appropriate type.

For the %s specifier these extracted characters are:

Any number of non-whitespace characters, stopping at the first whitespace character found. A terminating null character is automatically added at the end of the stored sequence.

So when the "non-whitespace characters" and "terminating null character" is stored, there will be a segfault. Which is exactly what Visual Studio will yield (you can test that this fails at http://webcompiler.cloudapp.net/):

enter image description here

Now as far as non-Visual Studio compilers, libc's extraction code for the %s specifier: https://github.com/ffainelli/uClibc/blob/master/libc/stdio/_scanf.c#L1376 has the leading comment: /* We might have to handle the allocation ourselves */ this is because:

The GNU C library supported the dynamic allocation conversion specifier (as a nonstandard extension) via the a character. This feature seems to be present at least as far back as glibc 2.0.
Since version 2.7, glibc also provides the m modifier for the same purpose as the a modifier.

[Source]

So because libc extracts to a buffer constructed internally to sscanf and subsequently checks that the buffer parameter has no flags set before assigning it, it will never write characters to a NULL buffer parameter.

I can't stress enough that this is non-standard, and is not guaranteed to be preserved even between minor library updates. A far better way to do this is to use the * sub-specifier which:

Indicates that the data is to be read from the stream but ignored (i.e. it is not stored in the location pointed by an argument).

[Source]

This could be accomplished like this for example:

s == NULL ? sscanf("Privjet mir!", "%*s") : sscanf("Privjet mir!", "%s", s);

Obviously the true-branch of the ternary is a no-op, but I've included it with the expectation that other data was expected to be read from the string.

美人骨 2024-10-27 02:29:53

联机帮助页指出,当使用 %s 时,参数必须是一个具有足够空间容纳字符串和 \0 的指针。所以我的猜测是你的情况的行为是未定义的。它可能会起作用,也可能会崩溃或损坏内存并在以后引起问题。

The manpage says that, when using %s, the argument must be a pointer with enough space for the string and \0. So my guess would be that the behaviour in your case is undefined. It may work, it may also crash or corrupt memory and cause issues later.

肥爪爪 2024-10-27 02:29:53

不,这是不允许的。
sscanf %s 需要一个 char* 指向足够大的缓冲区,printf %s 需要一个 nul char* 缓冲区。其他任何事情都会导致未定义的行为。 (这意味着某些实现可能会以某种方式检测和处理空指针,其他实现可能不会)

No, this is not allowed.
sscanf %s expects a char* pointing to a sufficient large buffer, printf %s wants a nul char* buffer. Anything else results in undefined behavior. (And that means some implementations might detect and handle a null pointer in a certain way, other implementations might not)

怂人 2024-10-27 02:29:53

我在标准中没有找到任何明确涉及 NULL*printf/*scanf 的内容。

我认为这是未定义的行为1,因为它被视为传递与格式说明符不一致的参数(§7.19.6.1 ¶13、§7.19.6.2 ¶13): %s 意味着您将传递一个指向字符数组第一个元素的指针(对于 *scanf 获取的字符串来说足够大,包含一个 NUL< /code> 终止的字符串为 *printf) - 并且传递 NULL 不能满足此要求。


1. In this case UB shows as "just ignoring the acquisition" and "printing (null)", on other platforms it may result in planes falling down the sky or the usual nasal demons.

I didn't find anything in the standard explicitly concerning NULL and *printf/*scanf.

I suppose that this is undefined behavior1, since it counts as passing an argument that is not coherent with the format specifier (§7.19.6.1 ¶13, §7.19.6.2 ¶13): %s means that a you're going to pass a pointer to the first element of a character array (large enough for the acquired string for *scanf, containing a NUL-terminated string for *printf) - and passing NULL doesn't satisfy this requirement.


1. In this case UB shows as "just ignoring the acquisition" and "printing (null)", on other platforms it may result in planes falling down the sky or the usual nasal demons.

挖个坑埋了你 2024-10-27 02:29:53

将内存分配给 s 。将 s 分配给字符数组。然后运行程序。
以下将起作用。

int main(int arc, char* argv[])
{
  char s[100];
  sscanf("Privjet mir!", "%[^\t]s", s);
  printf("s: %s\n", s);
  return 0;
}

Allocate the memory to s . Assign s to character array. Then run the program.
Following will work.

int main(int arc, char* argv[])
{
  char s[100];
  sscanf("Privjet mir!", "%[^\t]s", s);
  printf("s: %s\n", s);
  return 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文