微软的一些安全功能的C++ 11的一部分,所以他们现在应该可以移植。 安全功能和传统安全功能之间的一个重要区别是异常行为,有时是返回值。许多程序员都没有注意到;这些差异往往被忽视。 例如snprintf的除外行为是从_snprintf_s不同:
snprintf
返回缓冲器的大小无关,打印字符串,而不是 计数终止空字符所需的字符数。 我不认为snprintf的自筹例外,但无效的内存访问 会。
_snprintf_s
返回相同的值的snprintf如果抛光轮是足够大的,但 如果浅黄色过少,或浅黄色或FMT是NULL指针,_snprintf_s调用 无效参数处理程序,设置分别的errno = ERANGE或EINVAL, 并返回-1。 如果在遗留代码中异常行为很重要,请注意将旧传统功能转换为安全版本。
我用微软的安全“_s”功能挣扎了几年,尤其是写作已编译在Visual Studio中的Windows平台和使用gcc /克+ +“nix平台代码时。这也是重新使用旧的源代码时,因为这是一个苦差事通过代码改变的fprintf中疼痛()来fprintf_s()等。_CRT_SECURE_NO_DEPRICAT宏观抑制废弃警告,但我从来没有关闭了编译器的粉丝警告没有解决根本问题;警告是由于某种原因而发布的。
我的临时补丁(我承认我仍然不时使用的)是一个包含文件全宏和一些内联函数映射的传统和安全功能。当然映射不会模仿异常行为和返回值。如果你愿意,你可以编写函数来模仿它,但是在某些时候,使用安全函数和改变你的旧代码来做同样的事情会更容易。而且,一些安全功能不容易被映射,例如, sprinf sprintf_s。
这是我的包含文件(比代码更多的评论,但值得一读,他们恕我直言):
#pragma once
#if !defined(FCN_S_MACROS_H)
#define FCN_S_MACROS_H
///////////////////////////////////////////////////////////////////////////////
//
// These macros provide (partial) compatibility of source code developed
// for older MSVC versions and non-MSVC c++ compilers for some of Microsoft's
// security enhanced funcions, e.g. fscanf_s, sscanf_s, printf_s, strcpy_s,
// fopen_s.... Of course the standard functions still work in MSVS, but
// the choice is either to live with the annoying warning messages (bad idea)
// or set a compiler directive to stop the warnings (bad idea--there might
// important warnings as well as the annoying ones).
//
// It looks like a lot of the secure functions are now part of C++11. Those
// functions should be used in new code. The macros below can be used for
// for as a bridge for older code, but at some point it would be best to
// upgrade the code with the more secure functions. Eventually, the depricated
// functions may be removed, but probably not for a long time.
//
// Bill Brinson
// 21 February 2011 (updated once or twice since then).
//
///////////////////////////////////////////////////////////////////////////////
// Does It Work:
//
// *** No warranty expresed nor implied. Use at your own risk. ***
//
// I've tested most of the standard function to MS specific macros. They
// work in my codes so far, but Murphy says ...
//
// I usually write code in MSVS, using the standard functions, then port to
// linux if needed. I haven't though as much about the inverse macros,
// nor have I tested all of them. They seem unnecessary anyway. Too bad: they
// tend to be simpler.
// Test the macros yourself, and investigate exception behaviors before using
// them.
//
///////////////////////////////////////////////////////////////////////////////
//
// String Functions With No Count Parameter:
//
// The string functions that don't specify the maximum number of bytes to copy
// into the buffer (sprintf, strcpy, ...) are a problem. Using the sizeof()
// operator is a terrible idea (I should know--I though of it myself.
// Fortunately sanity prevailed before I used it in real code.
// In case you are tempted: the sizeof(buff) method WILL FAIL at runtime
// if buffer is not defined as an array (char cstring[32] or similar). For
// dynamically allocated memory, sizeof(ptr) returns the size of the pointer
// itself, not the allocated memory, so if your are copying no more than four
// bytes and you allocated at least that many, it would work due to blind luck.
// _memsize() (MS specific, but that's were it's needed) can be used for
// memory allocated with malloc, calloc, or realloc, but it doesn't work
// for char buff[size] or memory allocated with the new opperator. Does anyone
// still use malloc()?
// Overloaded functions taking char[] and *char to differentiate them might
// work for arrays and pointers to memory allocated by malloc et. al., but not
// for pointers to memory allocated by new (which have the same type, so not
// differentiated by the overloaded functions).
// If someone an idea, please let me know.
//
// This should only be an issue for legacy code; use snprintf, strncpy, etc.
// in new code (which you already do, right?), and make sure count has an
// appropriate value. For legacy code containing sprintf, strcpy, etc.,
// I've decided to just bite the bullet: let the MS compiler point out the
// unsafe functions, then change them to the safer (but standard) versions
// that specify the allowable number of bytes to copy.
//
///////////////////////////////////////////////////////////////////////////////
// Exception Behavior:
//
// This is an important difference between the MS decreed safe functions and
// the traditional C/C++ functions.
// I suspect all of the MS specific functions have different exception behaviors.
// For example the exception behavior of snprintf is different from _snprintf_s:
// snprintf returns the number of characters required to print the string, not
// counting the terminating null character, regardless of the size of the buffer.
// I don't think snprintf raises exceptions.
//
// _snprintf_s returns same value as snprintf if buff is sufficiently large, but
// if 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 return values and exception behaviors are important in your code, create
// your own functions to handle the conversions.
//
///////////////////////////////////////////////////////////////////////////////
// Overloads:
//
// The macros below handle only the most common (for me, at least) overloads.
//
///////////////////////////////////////////////////////////////////////////////
// Suggetions:
//
// Yes please. There are a ton of these MS specific "safe" functions. I've
// only done a few.
//
///////////////////////////////////////////////////////////////////////////////
// License:
//
// I suppose someone might care about this.
// Sure, use what you like, delete what you don't. Modify it to your hearts
// content.
// I wouldn't mind getting an attaboy or something if it works (not required).
// If it doesn't work, blame MS.
//
///////////////////////////////////////////////////////////////////////////////
// #include <cstdlib> // Do I need cstdlib? Hmm...maybe for sizeof()?
#include <cstdio>
#include <string> // Need this for _stricmp
using namespace std;
// _MSC_VER = 1400 is MSVC 2005. _MSC_VER = 1600 (MSVC 2010) was the current
// value when I wrote (some of) these macros.
#if (defined(_MSC_VER) && (_MSC_VER >= 1400))
// The function plus macro strategy could be used for most of the offending
// MS functions, particularly for maintaining consistent exception behaviors
// and return values. T
// inline is for run time efficiency, but the compiler is not
// constrained to comply.
inline extern
FILE* fcnSMacro_fopen_s(char *fname, char *mode)
{ FILE *fptr;
fopen_s(&fptr, fname, mode);
return fptr;
}
#define fopen(fname, mode) fcnSMacro_fopen_s((fname), (mode))
inline extern
char* fcnSMacro_strtok_s(char *strng, char *delimiters)
{ static char *cntx; // This static variable causes the same problem
// as the original strtok: can't alternate search
// strings in the same process (MS says "thread").
if(strng != NULL) *cntx = NULL;
char *cptr = strtok_s(strng, delimiters, &cntx);
return cptr;
}
#define strtok(strng, delim) fcnSMacro_strtok_s((strng), (delim))
#define fcloseall() _fcloseall()
// I substituded count+1 for snprintf's buffer size argument. For well
// written code, the buffer size should be at least one more than count
// to leave room for the terminating '\0'.
#define snprintf(buff, count, ...) _snprintf_s((buff), (count+1), (count), __VA_ARGS__)
#define printf(...) printf_s(__VA_ARGS__)
#define fprintf(fptr, ...) fprintf_s((fptr), __VA_ARGS__)
// I don't have a solution for mapping sprinf to sprintf_s. There are other
// functions like this.
// #define sprintf ???
// #define strcpy(s1, s2) ???
// These mappings look trivial, but the secure functions likely have different
// exception behaviors and maybe different return values.
#define fscanf fscanf_s
#define sscanf sscanf_s
#define scanf scanf_s
// strcmpi is deprecated in VS 2015. Don't know about 2013 or 2014
#define strcmpi _stricmp
// No conversion needed for strncmp (yet). I guess MS hasn't gotten around
// to it yet.
// #define strncmp ???
#define strncpy(dest, source, count) strcpy_s((dest), (count), (source))
#define strncat(dest, source, count) strcat_s((dest), (count), (source))
#else
// I usually write code in MSVS, using the standard functions, then port to linux if needed.
// I haven't though as much about the inverse macros, nor have I tested all of them.
// Test them yourself and investigate exception behaviors before using them.
#define fscanf_s fscanf
#define sscanf_s sscanf
#define scanf_s scanf
#define printf_s printf
#define sprintf_s snprintf
#define fprintf_s fprintf
#define strcpy_s(dest, count, source) strncpy((dest), (source), (count))
#define fopen_s(fp, fmt, mode) *(fp)=fopen((fmt), (mode))
#define _fcloseall fcloseall
#define strtok_s strtok
#define _strcmpi strcmpi
#endif //_MSC_VER
#endif // FCN_S_MACROS_H
权,_MSC_VER的适当临界值是1400,即MSVC 2005年我用MSVC 2010(_MSC_VER = 1600)时,我开始编写宏来处理不兼容的安全功能。我怀疑我会再次使用2005年,但有人会。精确是件好事。 – riderBill 2016-02-04 03:40:49
谢谢。我在函数宏包含文件中没有任何四个函数。是否已将_sntprintf_s_s测试为_sntprintf映射?我没有想到椭圆在RHS上工作。 – riderBill 2016-02-04 03:53:04
此外,_sntprintf_s到_sntprintf宏应该读'的#define _sntprintf_s(A,B,C,...)_sntprintf((a)中,(c)中,__VA_ARGS __)'。否则,当格式后面没有参数时,您将会挂起一个逗号(语法错误)。我想这对于sprintf函数调用来说是个不寻常的例子。 strncpy将是可能的选择。围绕rhs上的参数的额外括号是函数宏的良好习惯;没有他们,你会在某天得到意想不到的结果。根据墨菲的说法,这将是最糟糕的一天。 – riderBill 2016-02-04 04:13:12