%ms和%s scanf之间的差异

ron*_*ino 4 c gcc glibc scanf

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

一个可选的'm'字符.这用于字符串转换(%s,%c,%[),

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

chq*_*lie 7

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

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

一个可选a字符.这与字符串转换一起使用,并且释放调用者需要分配相应的缓冲区来保存输入:相反,scanf()分配足够大小的缓冲区,并将此缓冲区的地址分配给相应的指针参数,该参数应该是指向char *变量的指针(在调用之前不需要初始化此变量).

free当不再需要时,调用者应该随后使用此缓冲区.这是一个GNU扩展; C99使用该a字符作为转换说明符(它也可以在GNU实现中使用).

手册页的NOTES部分说:

a,如果程序被编译与改性剂是不可用gcc -std=c99gcc -D_ISOC99_SOURCE(除非 _GNU_SOURCE 也被指定),在这种情况下,a被解释为说明符浮点数(见上文).

从版本2.7开始,glibc也提供了与m修饰符相同用途的修饰符.该m改性剂具有以下优点:

  • 它也可以应用于%c转换说明符(例如%3mc).

  • 它避免了%a浮点转换说明符的模糊性(并且不受其他影响gcc -std=c99)

  • 它在即将发布的POSIX.1标准版本中指定.

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

一个可选的'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);
Run Code Online (Sandbox Code Playgroud)

导致scanf从标准输入中解析一个单词并分配足够的内存来存储其字符和终止'\0'.的指针分配阵列将被存储到pscanf()将返回1,除非没有非空白字符可以读取stdin.

完全有可能其他系统使用m相似的语义或完全不同的东西.非标准扩展是不可移植的,在标准方法繁琐不切实际或完全不可能的情况下,应非常谨慎地使用,如此记录.

请注意,使用以下标准版本解析任意大小的单词确实是不可能的scanf():

您可以解析具有最大大小的单词,并应指定在以下位置之前存储的最大字符数'\0':

    char buffer[20];
    scanf("%19s", buffer);
Run Code Online (Sandbox Code Playgroud)

但这并没有告诉您在标准输入中可以解析多少字符.在任何情况下,如果输入足够长,则不传递最大字符数可能会调用未定义的行为,并且攻击者甚至可能使用特制输入来破坏您的程序:

    char buffer[20];
    scanf("%s", buffer); // potential undefined behavior,
                         // that could be exploited by an attacker.
Run Code Online (Sandbox Code Playgroud)

  • 它是POSIX 2013标准的一部分 - 因此任何符合该标准的系统都将支持它. (3认同)