%ms 和 %s scanf 之间的区别

9

阅读 scanf 手册时,我遇到了这一行:

一个可选的'm'字符。这与字符串转换 (%s, %c, %[) 一起使用,

有人可以用简单的例子解释一下它的区别和在某些情况下需要使用此选项的原因吗?


你以为我只看了第一行吗?!-_-老实说,我没懂。所以我想要一个简单的例子和简单的解释来说明区别。 - rondino
char word[32]; scanf("%31s", word);/* 输入的最大字符数已知。 */ - BLUEPIXY
2
  1. char *word; scanf("%ms", &word);/* 输入大小未知,根据输入动态分配内存空间。 */
- BLUEPIXY
2
我不想听起来很苛刻,但这是你的问题给人的印象。这段文字很好地解释了区别。如果你没有理解某个特定的短语,为什么不提一下呢? - n. m.
我在C语言方面仍然是一个初学者,我正在尽我最大的努力去理解它。我讨厌读一些东西,就像那样跳过它!我真的很感激!非常感谢@BLUEPIXY - rondino
1个回答

11
C标准中没有在scanf()格式中定义这种可选字符。GNU lib C为字符串转换定义了一个可选的a指示符,如下所示(来自scanf的man页面):
可选的a字符。这与字符串转换一起使用,并减轻调用者分配相应缓冲区以容纳输入的需要:相反,scanf()分配足够大小的缓冲区,并将此缓冲区的地址分配给相应的指针参数,该参数应该是指向char *变量的指针(在调用之前不需要初始化此变量)。当不再需要时,调用者应随后释放此缓冲区。这是GNU扩展;C99将a字符用作转换说明符(在GNU实现中也可以将其用作此类说明符)。
man页面的NOTES部分说:
如果使用gcc -std=c99gcc -D_ISOC99_SOURCE编译程序,则a修饰符不可用(除非也指定了_GNU_SOURCE),此时a将被解释为浮点数的说明符(参见上文)。自2.7版本以来,glibc还提供了m修饰符,用于相同的目的。 m修饰符具有以下优点:
  • 它也可以应用于%c转换说明符(例如%3mc)。

  • 它避免了与%a浮点转换说明符有关的歧义(并且不受gcc -std=c99等的影响)

  • 它在即将发布的POSIX.1标准修订版中进行了规定。

在线Linux手册页面 http://linux.die.net/man/3/scanf 仅记录了以下选项:

一个可选的 'm' 字符。这适用于字符串转换 (%s, %c, %[),并减轻了调用者分配相应缓冲区以容纳输入的需要:相反,scanf() 分配足够大小的缓冲区,并将该缓冲区的地址赋值给相应的指针参数,该参数应为指向 char * 变量的指针 (在调用之前不需要初始化此变量)。调用者在不再需要时应使用 free(3) 释放此缓冲区。

Posix标准在其POSIX.1-2008版本中记录了此扩展 (请参见http://pubs.opengroup.org/onlinepubs/9699919799/functions/fscanf.html):

%c%s%[ 转换说明符可以接受一个可选的赋值分配字符 m,它将导致分配一个内存缓冲区来保存转换后的字符串,包括一个终止空字符。在这种情况下,相应于转换说明符的参数应该是一个指向指针变量的引用,该变量将接收指向已分配缓冲区的指针。系统将分配一个缓冲区,就像调用了 malloc() 一样。应用程序负责在使用后释放内存。如果没有足够的内存来分配缓冲区,则函数将设置 errno 为 [ENOMEM],并将导致转换错误。如果函数返回 EOF,则在函数返回之前,通过此调用使用赋值分配字符 m 成功分配的任何内存都将被释放。

使用此扩展,您可以编写:

char *p;
scanf("%ms", &p);

使scanf从标准输入中解析一个单词并分配足够的内存以存储其字符及终止符'\0'。指向分配数组的指针将被存储到p中,除非无法从stdin读取任何非空格字符,否则scanf()将返回1
其他系统完全有可能使用m来表示类似的语义或完全不同的内容。非标准扩展是不可移植的,应该非常小心地使用,并在标准方法笨重、不切实际或根本不可能的情况下进行记录。
请注意,使用标准版本的scanf()确实无法解析任意大小的单词:
您可以解析具有最大大小的单词,并应在'\0'之前指定要存储的字符的最大数量:
char buffer[20];
scanf("%19s", buffer);

但这并不能告诉您有多少个字符可以在标准输入中解析。无论如何,如果输入足够长,则不传递最大字符数可能会导致未定义的行为,而特意设计的输入甚至可能被攻击者用来破坏您的程序:
char buffer[20];
scanf("%s", buffer); // potential undefined behavior,
                     // that could be exploited by an attacker.

4
符合POSIX 2013标准的任何系统都支持它。 - Chris Dodd
它可以在网上访问这里 - Chris Dodd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接