什么是StringCbprintf,它与一般sprintf有何不同?

What is StringCbprintf and how's this different than general sprintf?

本文关键字:sprintf 何不同 StringCbprintf 什么      更新时间:2023-10-16

我正在浏览以前编写的代码,我发现了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注释。它们可以与/analyze编译器选项一起使用,并且可以帮助识别错误和问题,如原始 C 缓冲区和指针的缓冲区溢出等。除了有关 SAL 的 MSDN 文档外,您还可以阅读此博客文章。

具有讽刺意味的是(并且错误地)有人写道:

"在世界其他地方,输入是常量指针,但我想 太简单了。:)">

忽略了SAL比这更强大的事实。实际上,使用 SAL,您还可以指定目标缓冲区的最大大小,指示哪个参数包含目标缓冲区大小;例如,如果您打开<strsafe.h>标头,您可以读到用于StringCbPrintfW的实际 SAL 注释(StringCbPrintf的 Unicode 版本)是这样的:

STRSAFEAPI
StringCbPrintfW(
__out_bcount(cbDest) STRSAFE_LPWSTR pszDest,
__in size_t cbDest,
__in __format_string STRSAFE_LPCWSTR pszFormat,
...)
{
....

请注意应用于pszDest参数的__out_bcount(cbDest)SAL注释如何指定这是指向输出缓冲区(__out)的指针,其大小由参数cbDest以字节(_bcount)表示。如您所见,这是一个丰富的注释(比简单的"const"或"nonconst"更丰富)。

在我看来,如果您使用强大的容器类(如std::vectorstd::string编写C++代码,则 SAL 毫无用处,它们知道自己的大小等。但是SAL在带有原始指针(如几个Win32 API)的C-ish代码中很有用。

关于您问题的第二部分:

"如果我们已经有了sprintf,为什么我们需要StringCbPrintf">

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

文档试图为您解释这一点:

与它所取代的函数相比,StringCbPrintf 为 代码中适当的缓冲区处理。缓冲区处理不当与许多涉及缓冲区溢出的安全问题有关。StringCbPrintf 始终以 null 结尾的非零长度目标缓冲区。

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

正如这里所说:

StringCbPrintf 是以下函数的替代品:

  • sprintf, swprintf, _stprintf
  • wsprintf
  • wnsprintf
  • _snprintf、_snwprintf_sntprintf

因此,它不仅取代了sprintf,而且还取代了那些与wchar一起工作的,例如。它还引入了额外的缓冲区处理以防止缓冲区溢出(如同一 msdn 文章中所述)。它还始终以 null 终止目标缓冲区。_in__out_可以向您展示哪些参数是输入参数,哪些参数是输出参数。这些很可能#define为无,并在编译开始之前消失。