scanf和scanf_s的区别

35

scanfscanf_s有什么区别?在大学里我学的是并一直使用的是scanf,但在我的个人电脑上,Visual Studio一直发出这个警告。

 error C4996: 'scanf': This function or variable may be unsafe. Consider using scanf_s instead.

我必须将所有的scanf更改为scanf_s,否则程序无法构建。 (我正在使用Visual Studio 2013)


1
可能是[Scanf_s警告?跳过用户输入(主题:Runge-Kutta,流行病模拟)]的重复问题。(链接:http://stackoverflow.com/questions/9986776/scanf-s-warning-skips-user-inputs-topics-runge-kutta-epidemic-simulation) - Andreas Fester
1
它与 scanf 相同,只是不会导致缓冲区溢出。 - David Ranieri
1
请查看此链接:http://msdn.microsoft.com/zh-cn/library/w40768et(v=vs.90).aspx。 - BLUEPIXY
3个回答

41

这是一个专属于Microsoft编译器的函数。

scanf最初只是读取你键入的控制台输入并将其分配给变量类型。

如果你有一个名为first_name [5]的数组,并使用scanf输入"Alex",那没有问题。但如果你使用相同的数组并输入"Alexander",你会发现它超出了数组包含的5个插槽,所以C仍然会将其写入不属于该数组的内存中,这可能导致程序崩溃,具体取决于是否有东西尝试访问并写入不属于first_name的内存槽。这就是scanf_s发挥作用的地方。

scanf_s有一个参数(参数),您可以在其中指定缓冲区大小并实际控制输入限制,以避免使整个程序崩溃。


8
“where you can specify the buffer size" -> 这是错误的。 正确的是:"你必须为所有类型为 c、C、s、S 或 [ 的输入参数指定缓冲区大小。" 因此,仅将后缀“_s”添加到使用 scanf("...%s...", ...) 的程序中会导致编译时没有警告,但实际上什么也没做,因为假定缓冲区大小为0,因此不会读取任何数据。 - Palo
1
实际上,在Visual Studio中,如果没有缓冲区长度参数,编译器会在使用%s%c时发出警告。 - Anders Marzi Tornblad
2
"_s" 函数现在已成为 C11 的一部分,并且具有可移植性。 - Dai
5
_s 函数现在已成为 C11 的一部分并且可移植。Annex K 是可选的,而 Microsoft 实现则不可移植。根据《Annex K 与界限检查接口的实战经验》(Field Experience With Annex K — Bounds Checking Interfaces): “Microsoft Visual Studio 实现了较早版本的 API,但该实现是不完整的,既不符合 C11 标准也不符合原始的 TR 24731-1 标准...由于许多偏离规范的地方,Microsoft 实现不能被认为是符合标准或者可移植的。” - Andrew Henle

12

scanf_s()在C99标准(以及之前的标准)中没有被描述。

如果您想使用面向C99(或之前版本)的编译器,请使用scanf()

对于C11标准(以及以后的标准),scanf_s()scanf()更难使用,但可以提供更好的安全性以防止缓冲区溢出问题。

C11 fscanf_s(): http://port70.net/~nsz/c/c11/n1570.html#K.3.5.3.2

~~~~~~~~~~~~~~~~

如果您有一个提供scanf_s()作为扩展功能的C99编译器,并且不介意失去可移植性,请检查您的编译器文档。


3
请注意,C11标准的附录K是可选的。一种实现可以声称符合C11标准,但不提供scanf_s()函数(您可以使用#if defined(__STDC_LIB_EXT1__)来检查)。 - pmg
3
我不认为使用起来“更加困难”。只需在扫描字符串或字符时提供缓冲区大小即可,这本应该是你已经在做的事情! - Anders Marzi Tornblad

0
你可以做的避免这个错误的方法是将<_CRT_SECURE_NO_WARNINGS>粘贴到一个地方。 要进入该位置,请在解决方案资源管理器中右键单击项目,然后单击属性。 然后转到配置属性,然后转到c / c ++,然后转到预处理器。 然后在预处理器定义中,在所有内容之后添加分号并粘贴该内容。 然后按应用和确定。 你的问题应该得到解决。

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