8

我正在浏览以前编写的代码,我发现了StringCbPrintf()函数

我在msdn现场找到了这样的声明:

HRESULT StringCbPrintf(
  _Out_  LPTSTR pszDest,
  _In_   size_t cbDest,
  _In_   LPCTSTR pszFormat,
  _In_    ...
);

什么是_in__out_这里?

当我们已经拥有它时,为什么还需要它sprintf()

4

3 回答 3

9

_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) 的指针,其大小由参数以字节( )表示。如您所见,这是一个丰富的注释(比简单的“ ”或“非”更丰富)。_bcountcbDestconstconst

std::vector在我看来,如果您使用诸如or之类的健壮容器类std::string(它们知道自己的大小等)来编写 C++ 代码,那么 SAL 有点用处。但是 SAL 在带有原始指针的 C-ish 代码(如几个 Win32 API)中很有用。

关于你问题的第二部分:

StringCbPrintf“如果我们已经拥有,为什么还需要sprintf

主要原因是这sprintf是一个不安全且易于缓冲区溢出的功能;相反,StringCbPrintf您必须指定目标缓冲区的最大大小,这有助于防止缓冲区溢出(这是安全敌人)。

于 2012-11-07T14:28:12.437 回答
3

该文档试图为您解释:

与它替换的函数相比,StringCbPrintf 为代码中的正确缓冲区处理提供了额外的处理。缓冲区处理不佳与许多涉及缓冲区溢出的安全问题有关。StringCbPrintf 总是以空值结尾的非零长度目标缓冲区。

Microsoft API:s 中使用__In__and__Out__装饰器来表示如何使用指针参数。在世界其他地方,输入是const指针,但我想这太简单了。:)

于 2012-11-07T11:50:34.450 回答
2

正如这里所说:

StringCbPrintf 是以下函数的替代品:

  • sprintf, swprintf, _stprintf
  • wsprintf
  • wnsprintf
  • _snprintf, _snwprintf, _sntprintf

因此,它不仅可以替换sprintf,还可以替换那些与之一起工作的wchar,例如。它还引入了额外的缓冲区处理以防止缓冲区溢出(如同一篇 msdn 文章中所述)。它也总是以空值终止目标缓冲区。_in__out_在那里向您显示哪些参数是输入参数,哪些是输出参数。那些很可能#define没有,并且在编译开始之前就消失了。

于 2012-11-07T11:51:26.780 回答