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