我正在阅读以前编写的代码,并找到了StringCbPrintf()
函数
我在msdn
网站上发现了这样的声明:
HRESULT StringCbPrintf(
_Out_ LPTSTR pszDest,
_In_ size_t cbDest,
_In_ LPCTSTR pszFormat,
_In_ ...
);
这里的_in_
和_out_
是什么?
为什么在我们已经有sprintf()
时需要它?
答案 0 :(得分:8)
_In_
和_Out_
(注意:既没有_in_/_out
_也没有__In__/__Out__
_,也没有带有双重下划线的/analyze
,正如其他人写的那样回答)所谓的 SAL注释。它们可以与<strsafe.h>
编译器选项一起使用,并且可以帮助识别缓冲区溢出等错误和问题,以及原始C缓冲区和指针。除了MSDN documentation on SAL之外,您还可以阅读此blog post。
有人讽刺地(并且错误地)写道:
“在世界其他地方,输入是常量指针,但我猜是这样 太简单了。 :)“
错过了SAL比更强大的事实。事实上,使用SAL,您还可以指定目标缓冲区的最大大小,指示哪个参数包含目标缓冲区大小;例如如果您打开StringCbPrintfW
标题,您可以读到用于StringCbPrintf
(STRSAFEAPI
StringCbPrintfW(
__out_bcount(cbDest) STRSAFE_LPWSTR pszDest,
__in size_t cbDest,
__in __format_string STRSAFE_LPCWSTR pszFormat,
...)
{
....
的Unicode版本)的实际SAL注释是这样的:
__out_bcount(cbDest)
注意应用于pszDest
参数的__out
SAL注释如何指定这是指向输出缓冲区(_bcount
)的指针,其中 size 由参数cbDest
表示,以字节为单位(const
)。正如您所看到的,这是一个丰富的注释(比简单的“const
”或“非std::vector
”更丰富。)
在我看来,如果用可靠的容器类(例如std::string
或StringCbPrintf
)编写C ++代码,那么SAL就没用了,这些容器类知道它们自己的大小等等。但SAL在C-中很有用。带有原始指针的代码(如几个Win32 API)。
关于问题的第二部分:
“如果我们已经
,我们为什么需要sprintf
”sprintf
主要原因是StringCbPrintf
是不安全和缓冲区溢出功能;而是使用{{1}},您必须指定目标缓冲区的最大大小,这有助于防止缓冲区溢出(这是安全的敌人)。
答案 1 :(得分:2)
The documentation试图为您解释:
与它替换的函数相比,StringCbPrintf提供了额外的处理 代码中适当的缓冲区处理。缓冲区处理涉及缓冲区溢出的许多安全问题。 StringCbPrintf始终为null - 终止非零长度的目标缓冲区。
Microsoft API中使用__In__
和__Out__
修饰符:s表示如何使用指针参数。在世界其他地方,输入是const
指针,但我想这太简单了。 :)
答案 2 :(得分:2)
据说here:
StringCbPrintf是以下功能的替代品:
- sprintf,swprintf,_stprintf
- wsprintf
- wnsprintf
- _snprintf,_snwprintf,_sntprintf
因此,它不仅会替换sprintf
,还会替换为wchar
使用的_in_
。它还引入了额外的缓冲区处理以防止缓冲区溢出(如同一篇msdn文章中所述)。它还始终 null - 终止目标缓冲区。 _out_
和#define
用于显示哪些参数是输入参数,哪些参数是输出参数。那些很可能{{1}} d什么都没有,并且在编译开始之前就消失了。