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/43237996/

相关文章:

java - 使用 long 将指针从 JNI 传递到 Java

java - java中如何将对象写入文件?

python - Python 中的 C 扩展 - 返回 Py_BuildValue() 内存泄漏问题

c - 为什么在数组界限之外访问索引时,我的代码为什么不分段?

c - 执行 ELF IFUNC 调度函数时读取环境

c - 辅助线程中的信号处理

c - Glibc - ucontext.h 中的错误,但仅限于 -std=c11

c - 段错误的根本原因

c++ - *** 检测到 glibc *** free() : invalid pointer

centos - 找不到 GLIBC_2.7