转载自:
网页链接
VS中”This function or variable may be unsafe.”警告的解决办法。
问题原因
C语言的标准函数中,一些读取或写入内存的函数存在内存越界的问题,从而使得内存数据变得不安全。如scanf、gets、strcat等函数都存在着这样的问题。
为了避免这个问题,在VS中,另外提供了如scanf_s,get_s,strcat_s等相关的改进函数,来替代原来的标准函数的功能,并通过添加内存读取范围的限制来解决不安全的问题。
在实际的应用中,也许使用VS提供的安全函数会更加合理。但是,在学习中,几乎所有的课本以及教程都使用的原来的标准函数,另外考虑到移植性的问题,除了VS环境,其他环境中并没有提供改进后的函数。因此,我们通常任然需要标准的库函数来实现相关功能。
但是,如果在VS中使用原始的函数,编译器将会报错。这对使用和学习都带来了相当的不变。
问题分析
在VS2013中,以scanf为例。
如果在程序中使用了scanf函数,如下。
#include <stdio.h>。
int main()
char c[20];
scanf("%s", c);。
puts(c);
return 0;
编译将得到如下错误信息。
error C4996: ‘scanf’: This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.。
参见“scanf”的声明
错误信息的大意如下
此函数或变量可能不安全。
可以使用scanf_s代替该函数。
如果要取消禁用,请定义_CRT_SECURE_NO_WARNINGS。
更多信息请查看在线帮助
scanf的声明如下
_Check_return_ _CRT_INSECURE_DEPRECATE(scanf_s) _CRTIMP int __cdecl scanf(_In_z_ _Scanf_format_string_ const char * _Format, ...);。
在scanf的声明中,在函数的标准形式说明之前,还用到了几个宏定义,正是因为这几个宏定义才实现了scanf函数的禁用。
在VS中利用F12可以看到这几个宏的定义,宏定义具体内容如下。
sal.h
#define _Check_return_ _SAL2_Source_(_Check_return_, (), _Check_return_impl_)。
crtdefs.h
#define _CRT_INSECURE_DEPRECATE(_Replacement) _CRT_DEPRECATE_TEXT("This function or variable may be unsafe. Consider using " #_Replacement " instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.")。
crtdefs.h
#define _CRTIMP __declspec(dllimport)。
上面三个宏都包含了宏的嵌套调用,相关宏略多,因此在此不对其进行深入研究。
不过在第二个宏定义中,我们可以很容易发现在编译时,编译器向我们返回的错误信息。这进一步说明了scanf函数不能使用与这几个宏有关。
问题解决
在编译器给出的错误提示中,实际上已经为我们给出了一个明确的解决方案。我们只需要在程序的开头添加一个宏定义便能够解决问题。
#define _CRT_SECURE_NO_WARNINGS。
加入宏定义后,源代码变为如下形式。
#define _CRT_SECURE_NO_WARNINGS。
#include <stdio.h>。
int main()
char c[20];
scanf("%s", c);。
puts(c);
return 0;
再次进行编译,编译成功完成。
虽然按照上述的方法能够顺利解决问题,但是在实际的应用中,如果我们要求只能够使用标准库中的函数,而不能使用VS为我们提供的改进函数。那么我们每次在使用到相关函数时,都需要在文件前面,或者在头文件中添加相关宏。这样未免太麻烦。
既然我们不需要VS给我们提供的这个多余的改变,那有没有一个一劳永逸的办法解决这个问题呢。
方法是有的,这需要我们对VS的项目属性进行设置,具体步骤如下。
在项目属性设置中找到选项卡配置属性→C/C++→预处理器;。
在右侧的参数中找到预处理器定义,编辑其参数;。
在参数的末尾添加定义_CRT_SECURE_NO_WARNINGS。
这样,在编译器进行预处理时,预处理器就会自动在程序开头添加我们需要的宏定义,而不再需要我们手动添加。
在文件中不添加宏定义的情况下,再次进行编译。发现编译顺利完成。
这种方案因为修改的是项目的配置参数,因此适用于整个项目。在该项目中,将不再需要添加相关宏定义。但是其他项目自然不受该设置的影响,因此,如有需要,在其他项目中需要再次进行相同配置才能生效。
————————————————
版权声明:本文为CSDN博主「夏苍」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u012534008/java/article/details/54602774。
读入语句应该为:
scanf("%lf%lf",&x1,&x2);。
double量要使用%lf格式符,printf也一样。
scanf只是模式匹配函数,当你输入学号并回车时,只有学号保存到了str[i].num,剩余一个换行符留在缓冲区;
gets函数不会跳过任意空白符,但当只要遇到换行符就会停止,并用空字符替换换行符。
所以,你的gets函数根本就没有储存信息(它读取了上次遗留的换行符而终止了)
另外
scanf("%lf")中%lf是double类型的转换说明,你定义的结构体中却是float。
gets函数现在已经不推荐使用,应用fgets替代。
还有你的C代码很不标准,不符合c99。
你试试在你的scanf代码下面加上:
while (getchar() != '\n')。
;
方法一:在程序最前面加#define _CRT_SECURE_NO_DEPRECATE;
方法二:在程序最前面加#define _CRT_SECURE_NO_WARNINGS;
方法三:在程序最前面加#pragma warning(disable:4996);
方法四:把scanf改为scanf_s;.。
方法五:无需在程序最前面加那行代码,只需在新建项目时取消勾选“SDL检查”即可;
方法六:若项目已建立好,在项目属性里关闭SDL也行;
方法七:在工程项目设置一下就行;将报错那个宏定义放到 项目属性 -- C/C++-- 预处理器 -- 预处理器定义;
方法八:在 项目属性 -- c/c++ -- 命令行 添加:/D _CRT_SECURE_NO_WARNINGS 就行了。
我感觉这个的话就是一个产品型号,没有什么特殊的含义,你可以根据这个数字和字母就可以找到了。
相关信息:
码(code)是程序员用开发工具所支持的语言写出来的源文件,是一组由字符、符号或信号码元以离散形式表示信息的明确的规则体系。
代码设计的原则包括唯一确定性、标准化和通用性、可扩充性与稳定性、便于识别与记忆、力求短小与格式统一以及容易修改等。 源代码是代码的分支,某种意义上来说,源代码相当于代码。
现代程序语言中,源代码可以书籍或磁带形式出现,但最为常用格式是文本文件,这种典型格式的目的是为了编译出计算机程序。计算机源代码最终目的是将人类可读文本翻译成为计算机可执行的二进制指令,这种过程叫编译,它由通过编译器完成。
供把资料和指示输入自动计算机或制表机的任何符号系统;亦指这种符号的记录(如靠打孔资料卡片或磁带上的受磁点)。