【问题标题】:What is StringCbprintf and how's this different than general sprintf?什么是 StringCbprintf,这与一般的 sprintf 有何不同?
【发布时间】:2012-11-07 11:48:42
【问题描述】:

我正在查看之前编写的代码,发现StringCbPrintf()函数

我在msdn 网站上找到了这样的声明:

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

这里的_in__out_ 是什么?

既然我们已经有了sprintf(),为什么还需要它?

【问题讨论】:

  • 添加了“windows”和“winapi”标签,因为这个问题涉及到特定于 Windows 的 SAL 注释。
  • 请注意_in__out_ 不是有效的SAL(它们是_In__Out_,首字母大写)。另一种有效的 SAL 是带有前导双下划线(和小写首字母):__in__out

标签: c++ c windows winapi printf


【解决方案1】:

_In__Out_注意:既不是你写的_in_/_out_,也不是带有双下划线的__In__/__Out__,如其​​他答案中所写)被称为 SAL 注释。它们可以与 /analyze 编译器选项一起使用,并且可以帮助识别错误和问题,如缓冲区溢出等。原始 C 缓冲区和指针。除了MSDN documentation on SAL,你还可以阅读这个blog post

有人讽刺地(并且错误地)写道:

“在世界其他地方,输入是 const 指针,但我猜 太简单了。 :)"

忽略了 SAL 比这更强大的事实。实际上,使用 SAL 还可以指定目标缓冲区的最大大小,指示哪个参数包含目标缓冲区大小;例如如果您打开 <strsafe.h> 标头,您可以看到用于 StringCbPrintfWStringCbPrintf 的 Unicode 版本)的实际 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) 的指针,大小由参数cbDest 表示以字节为单位 (_bcount)。如您所见,这是一个丰富的注解(比简单的“const”或“非const”更丰富)。

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

关于你问题的第二部分:

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

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

【讨论】:

    【解决方案2】:

    The documentation 试图为你解释:

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

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

    【讨论】:

    • Nice ..这意味着__in__ 意味着const__out__ 用于输出缓冲区。但为什么需要它?我们有 sprintf 对吗?
    • +1 反正对于 inout ,我在想一种绑定参数,就像我们在数据库函数中一样
    • 请注意__In____Out__ 是错误的:有效的SAL 是__in/__out(指定here)或_In_/_Out_(指定here)。此外,-1 因为 SAL 比简单的const 正确性更丰富
    • 请注意,LPCTSTR pszFormat 已经包含一个 const(指向常量 tchar 字符串的长指针)。
    【解决方案3】:

    据说here:

    StringCbPrintf 是以下函数的替代:

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

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

    【讨论】:

    • 好这一行是用 msdn 写的,但问题在于 inout .. 无论如何 +1
    • @Omkant,在您可能读过的许多 C++ 书籍中,作者实际上建议区分输入和输出函数参数。一种解决方案是使用这样的宏,例如#define IN#define OUT。它们清楚地显示参数类型,并在编译开始之前消失。我不鼓励你这样做,这只是一些额外的信息:P
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-24
    • 1970-01-01
    • 1970-01-01
    • 2021-02-12
    • 2011-11-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多