详细介绍StringCchPrintf()

书籍:《Visual C++ 2017从入门到精通》的2.7 字符串

环境:visual studio 2022

内容:几个字符串类型->(将单字节char*转换为宽字节wchar_t *)

​**StringCchPrintf() 详解**

StringCchPrintf() 是 Windows API 中 ​StrSafe 系列的安全字符串操作函数之一,用于格式化字符串并安全地将结果写入目标缓冲区。其核心优势在于 ​防止缓冲区溢出,通过严格限制写入的字符数,避免传统函数(如 sprintf)的潜在安全漏洞。


函数原型

HRESULT StringCchPrintf(
  _Out_ LPSTR   pszDest,     // 目标缓冲区(ANSI)
  _In_  size_t  cchDest,     // 目标缓冲区大小(字符数,含 '\0')
  _In_  LPCSTR  pszFormat,   // 格式化字符串(ANSI)
  ...                        // 可变参数
);
Unicode 版本
HRESULT StringCchPrintfW(
  _Out_ LPWSTR  pszDest,
  _In_  size_t  cchDest,
  _In_  LPCWSTR pszFormat,
  ...
);

参数说明

参数类型描述
pszDestLPSTR/LPWSTR目标缓冲区指针,用于存储格式化后的字符串。
cchDestsize_t目标缓冲区的最大容量​(字符数,包含结尾的 \0)。
pszFormatLPCSTR/LPCWSTR格式化字符串(如 "Hello, %s!"),支持与 printf 相同的格式说明符。
...可变参数与 pszFormat 中占位符对应的参数。

返回值

  • 成功:返回 S_OK(0)。
  • 失败:返回错误码(如 STRSAFE_E_INSUFFICIENT_BUFFER 表示缓冲区不足)。

核心功能

  1. 安全格式化

    • 自动截断超出缓冲区容量的内容,确保不会溢出。
    • 严格限制写入的字符数(不超过 cchDest - 1,留出空间给 \0)。
  2. 错误处理

    • 通过返回值明确指示错误类型,避免未定义行为。

使用示例

1. 基础用法(ANSI)​
#include <strsafe.h>

void TestStringCchPrintf() {
    char buffer[20];
    HRESULT hr = StringCchPrintf(buffer, ARRAYSIZE(buffer), "Hello, %s!", "World");
    
    if (SUCCEEDED(hr)) {
        printf("Result: %s
", buffer); // 输出:Hello, World!
    } else {
        printf("Error: 0x%08X
", hr);
    }
}
2. Unicode 用法
#include <strsafe.h>

void TestStringCchPrintfW() {
    WCHAR buffer[20];
    HRESULT hr = StringCchPrintfW(buffer, ARRAYSIZE(buffer), L"Hello, %s!", L"World");
    
    if (SUCCEEDED(hr)) {
        wprintf(L"Result: %s
", buffer); // 输出:Hello, World!
    }
}
3. 缓冲区不足时的处理
char buffer[5];
HRESULT hr = StringCchPrintf(buffer, ARRAYSIZE(buffer), "This is a long string");
if (hr == STRSAFE_E_INSUFFICIENT_BUFFER) {
    printf("缓冲区不足,需要更大的空间!
");
}

与 sprintf_s 的对比

特性StringCchPrintf()sprintf_s
安全性更严格,自动截断溢出内容。需手动指定缓冲区大小,否则可能溢出。
返回值返回 HRESULT,明确错误类型。返回写入的字符数,需手动检查溢出。
代码页支持支持 ANSI 和 Unicode 版本。仅支持特定代码页(需手动转换)。

注意事项

  1. 缓冲区大小计算

    • 始终使用 ARRAYSIZE(buffer) 或显式指定缓冲区容量,避免硬编码。
    • 示例:
      char buffer[256];
      StringCchPrintf(buffer, sizeof(buffer), ...); // 错误!应使用 ARRAYSIZE(buffer)
      StringCchPrintf(buffer, ARRAYSIZE(buffer), ...); // 正确
  2. 格式说明符

    • 支持与 printf 相同的格式说明符(如 %d%s%x
    • 避免使用宽字符格式说明符(如 %ls)与非宽字符缓冲区混用。
  3. 错误处理

    • 必须检查返回值,处理可能的错误(如缓冲区不足)。
    • 示例:
      if (hr == STRSAFE_E_INSUFFICIENT_BUFFER) {
          // 动态扩展缓冲区并重试
      }

高级用法

1. 动态扩展缓冲区
void SafeFormatDynamic() {
    size_t initialSize = 64;
    char* buffer = (char*)malloc(initialSize);
    if (!buffer) return;

    HRESULT hr = StringCchPrintf(buffer, initialSize, "Initial: %s", "Hello");
    if (hr == STRSAFE_E_INSUFFICIENT_BUFFER) {
        free(buffer);
        initialSize *= 2;
        buffer = (char*)malloc(initialSize);
        // 重试...
    }
}
2. 追加字符串
void AppendString() {
    char buffer[100] = "Hello";
    size_t remaining = ARRAYSIZE(buffer) - strlen(buffer) - 1;
    StringCchPrintf(buffer + strlen(buffer), remaining, ", %s!", "World");
}

总结

场景解决方案示例代码
基础格式化直接调用 StringCchPrintfStringCchPrintf(buffer, size, "Hello %s", "World");
缓冲区不足检查 STRSAFE_E_INSUFFICIENT_BUFFER 并扩展缓冲区动态分配内存后重试
Unicode 支持使用 StringCchPrintfWStringCchPrintfW(buffer, size, L"%s", L"世界");

通过合理使用 StringCchPrintf(),可以有效避免传统字符串操作的漏洞,提升代码的安全性和健壮性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值