需要 #define 来包含安全字符串函数的 Visual Studio 版本(以避免 _CRT_SECURE_NO_DEPRECATE)
不久前,我尝试使用 Visual Studio 2010 编译一个 MFC 程序,该程序使用了我在 Visual Studio 2003 中编写的库。毫不奇怪,我收到了一堆关于弃用和使用各种字符串函数的安全版本的警告。
然后我更新了库中的相关函数以使用安全函数,并且它编译得很好。
后来我尝试在另一个系统上使用 Visual Studio 2003 再次编译它,但因为安全功能不存在而烦恼。
我决定创建一种混合方法,使我能够编译在任一环境中使用该库的程序,如果可用,则使用安全函数,如果不可用,则将它们别名为旧函数。
起初,我考虑检查每个函数以查看是否存在安全版本,但这行不通,并且需要为每个函数单独工作:
#ifndef strcpy_s
#define strcpy_s(a,b,c) strcpy(a,c)
#endif
#ifndef strcat_s
#define strcat_s(a,b,c) strcat(a,c)
#endif
…
所以我试图找出一种确定安全函数是否存在的方法。我知道它们是在 Visual Studio 2005 中引入的,但是是否有 #define
或可以按如下方式使用的东西?
#ifndef SECURE_FUNCTIONS // or #ifdef VS_VER_2005, #if (VS_VER >= 0x2005) etc.
#define strcpy_s(a,b,c) strcpy(a,c)
#define strcat_s(a,b,c) strcat(a,c)
…
#endif
我检查了 crtdefs.h
但没有发现任何有用的东西。
A while back I tried to use Visual Studio 2010 to compile an MFC program that used a library I had written in Visual Studio 2003. Not surprisingly, I got a bunch of warnings about deprecation and using the secure versions of various string functions.
I then updated the relevant functions in the library to use the secure functions and it compiled fine.
I later tried to compile it again on the other system with Visual Studio 2003 and got nagged about the secure functions not existing.
I decided to create a hybrid approach that would allow me to compile programs that use the library in either environment, making use of the secure functions if available, and if not, aliasing them to the old ones.
At first I considered checking each function to see if a secure version exists, but that won’t work and requires separate work for each and every function:
#ifndef strcpy_s
#define strcpy_s(a,b,c) strcpy(a,c)
#endif
#ifndef strcat_s
#define strcat_s(a,b,c) strcat(a,c)
#endif
…
So what I’m trying to figure out is a way to determine if the secure functions exist. I know that they were introduced in Visual Studio 2005, but is there a #define
or something that can be used as follows?
#ifndef SECURE_FUNCTIONS // or #ifdef VS_VER_2005, #if (VS_VER >= 0x2005) etc.
#define strcpy_s(a,b,c) strcpy(a,c)
#define strcat_s(a,b,c) strcat(a,c)
…
#endif
I checked crtdefs.h
but found nothing useful.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我找到了解决办法;
_MSC_VER
宏/定义使这变得简单。由于安全字符串函数是已添加到 Visual Studio 2005(VC++版本1400
,那么就足够了做这样的事情:现在,当代码在 VS2005+ 下编译时,它将具有额外的安全性,而当在 VS2003- 上编译时,它仍然会在不修改的情况下编译,尽管没有额外的安全性 。
这使得移植和更新变得更加容易,因为即使您还无法使用 VS2005+ 编译它们,您也可以更新库函数并在代码中使用安全字符串函数,这样当您升级编译器时,您就不会这样做 必须对库或代码进行任何更改才能获得好处,这也使得在旧版本和新版本的 Visual Studio 上同时处理相同的代码库变得更容易(至少在某种程度上)。
I found a solution; the
_MSC_VER
macro/define makes this simple. Since the secure string functions were added in Visual Studio 2005 (VC++ version1400
, then it is sufficient to do something like this:Now when the code is compiled under VS2005+, it will have the added security, and when compiled on VS2003-, it will still compile without modification, albeit without the extra security.
This makes porting and updating easier because you can update the library functions and use the secure string functions in the code even if you can’t compile them with VS2005+ just yet. This way when you do upgrade the compiler, you won’t have to make any changes to the library or the code to reap the benefits. It also makes it easier to work on the same code-base on older and newer versions of Visual Studio concurrently (at least to some degree).
Microsoft 的一些安全函数是 C++11 的一部分,因此它们现在应该是可移植的。
安全函数与传统函数之间的一个重要区别是异常行为,有时还包括返回值。许多程序员都不关注其中任何一个;这些差异常常被忽视。
例如,snprintf 的异常行为与 _snprintf_s 不同:
snprintf
返回打印字符串所需的字符数,而不是无论缓冲区的大小如何,都对终止空字符进行计数。
我不认为 snprintf 本身会引发异常,而是无效的内存访问
会。
如果 buff 足够大,
_snprintf_s
返回与 snprintf 相同的值,但是如果 buff 太小,或者 buff 或 fmt 是 NULL 指针,则 _snprintf_s 调用
无效参数处理程序,分别设置 errno = ERANGE 或 EINVAL,
并返回-1。
如果异常行为在您的遗留代码中很重要,那么当您从旧的传统函数转换为安全版本时请注意。
我在 Microsoft 的安全“_s”函数上苦苦挣扎了几年,尤其是在 Visual Studio 中编写为 Windows 平台编译的代码以及使用 gcc/g++ 为 'nix 平台编译的代码时。重用旧源代码时也很痛苦,因为将 fprintf() 更改为 fprintf_s() 等代码是一件苦差事。 _CRT_SECURE_NO_DEPRICAT 宏会抑制弃用警告,但我从来不喜欢关闭编译器警告而不解决根本问题;发出警告是有原因的。
我的临时补丁(我承认我仍然不时使用)是一个包含文件,其中充满了宏和一些内联函数来映射传统函数和安全函数。当然,映射不会模仿异常行为和返回值。如果您愿意,您也可以编写函数来模仿它,但在某些时候,使用安全函数并更改旧代码来执行相同的操作会更容易。此外,某些安全函数无法轻松映射,例如 sprinf 到 sprintf_s。
这是我的包含文件(注释比代码多,但值得一读,恕我直言):
Some of Microsoft's secure functions are part of C++11, so they should be portable now.
An important difference between the secure functions and the traditional ones are the exception behaviors, and sometimes the return values. Many programmers don't pay attention to either; those differences are often overlooked.
For example the exception behavior of snprintf is different from _snprintf_s:
snprintf
returns the number of characters required to print the string, notcounting the terminating null character, regardless of the size of the buffer.
I don't think snprintf itself raises exceptions, but an invalid memory access
would.
_snprintf_s
returns same value as snprintf if buff is sufficiently large, butif buff is too small, or buff or fmt is a NULL pointer, _snprintf_s invokes the
invalid parameter handler, sets errno = ERANGE or EINVAL, respectively,
and returns -1.
If exception behavior is important in your legacy code, pay attention when you convert from the old traditional functions to the secure versions.
I struggled with Microsoft's secure "_s" functions for a few years, especially when writing code that was compiled for Windows platforms in Visual Studio and for 'nix platforms using gcc/g++. It was also an pain when reusing old source code because it's a chore to go through the code changing fprintf() to fprintf_s(), etc. The _CRT_SECURE_NO_DEPRICAT macro suppresses the deprecation warnings, but I've never been a fan of shutting up compiler warnings without fixing the underlying problems; the warnings are issued for a reason.
My temporary patch (which I'll admit I still use from time to time) was an include file full of macros and a few inline functions to map the traditional and secure functions. Of course the mappings don't mimic the exception behaviors and return values. If you want, you could write the functions to mimic that also, but at some point it's just going to be easier to use the secure functions and change your old code to do the same. Also, some of the secure functions cannot be readily mapped, e.g. sprinf to sprintf_s.
Here's my include file (more comments than code, but worth reading them IMHO):