c - %ms 和 %s scanf 之间的区别

标签 c gcc glibc scanf

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

An optional 'm' character. This is used with string conversions (%s, %c, %[),

有人可以用简单的例子来解释它,说明这种选择在某些情况下的区别和需要吗?

最佳答案

C 标准没有在 scanf() 中定义这样一个可选字符格式。

GNU lib C 确实定义了一个可选的 a以这种方式指示(来自 scanf 的手册页):

An optional a character. This is used with string conversions, and relieves the caller of the need to allocate a corresponding buffer to hold the input: instead, scanf() allocates a buffer of sufficient size, and assigns the address of this buffer to the corresponding pointer argument, which should be a pointer to a char * variable (this variable does not need to be initialized before the call).

The caller should subsequently free this buffer when it is no longer required. This is a GNU extension; C99 employs the a character as a conversion specifier (and it can also be used as such in the GNU implementation).

手册页的注意部分说:

The a modifier is not available if the program is compiled with gcc -std=c99 or gcc -D_ISOC99_SOURCE (unless _GNU_SOURCE is also specified), in which case the a is interpreted as a specifier for floating-point numbers (see above).

Since version 2.7, glibc also provides the m modifier for the same purpose as the a modifier. The m modifier has the following advantages:

  • It may also be applied to %c conversion specifiers (e.g., %3mc).

  • It avoids ambiguity with respect to the %a floating-point conversion specifier (and is unaffected by gcc -std=c99 etc.)

  • It is specified in the upcoming revision of the POSIX.1 standard.

在线 linux 手册页位于 http://linux.die.net/man/3/scanf仅将此选项记录为:

An optional 'm' character. This is used with string conversions (%s, %c, %[), and relieves the caller of the need to allocate a corresponding buffer to hold the input: instead, scanf() allocates a buffer of sufficient size, and assigns the address of this buffer to the corresponding pointer argument, which should be a pointer to a char * variable (this variable does not need to be initialized before the call). The caller should subsequently free(3) this buffer when it is no longer required.

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

The %c, %s, and %[ conversion specifiers shall accept an optional assignment-allocation character m, which shall cause a memory buffer to be allocated to hold the string converted including a terminating null character. In such a case, the argument corresponding to the conversion specifier should be a reference to a pointer variable that will receive a pointer to the allocated buffer. The system shall allocate a buffer as if malloc() had been called. The application shall be responsible for freeing the memory after usage. If there is insufficient memory to allocate a buffer, the function shall set errno to [ENOMEM] and a conversion error shall result. If the function returns EOF, any memory successfully allocated for parameters using assignment-allocation character m by this call shall be freed before the function returns.

使用这个扩展,你可以写:

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

导致 scanf从标准输入解析一个单词并分配足够的内存来存储它的字符加上一个终止 '\0' .指向分配数组的指针将存储到 p 中和 scanf()会返回 1 , 除非无法从 stdin 读取非空白字符.

其他系统完全有可能使用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.

关于c - %ms 和 %s scanf 之间的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38685724/

相关文章:

c - SDL双重免费或损坏错误小代码段

c - 简单的 fork 和管道

c - 安装错误apache httpd 2.4.9

android - 如何链接 cpufeatures lib 以获取 native android 库?

prctl() 的正确使用方法

installation - 不同版本的glibc如何兼容?

c -++ 指针运算符

php - 将 PHP 5.3.3 从源代码编译到 Apache

c++ - 为什么 clang 或 gcc 不标记这种从 double 到 int 的隐式转换?

c++ - 在 GCC 中,如何(暂时)抑制来自 "#pragma message"的消息