[Windows]_[C/C++]_[避免使用wsprintf函数]

Posted infoworld

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Windows]_[C/C++]_[避免使用wsprintf函数]相关的知识,希望对你有一定的参考价值。

常景

  1. 之前在写WTL程序时,想在进度条里显示浮点数的百分比,但是百分比数字显示是错误的,用的sprintf的宽字节版本wsprintf。怎么回事?

  2. Windows开发时,由于std::string并没有格式化字符串的方法,因此我们只能使用sprintf。但是这个C标准库并不支持UNICODE字符串. 因此我们只能使用Windows提供的宽字节版本wsprintf。但是这个方法不能用,有什么问题?

说明

  1. 发现问题1,wsprintf[1]不支持对float类型的格式化,但是sprintf是支持的. 即便vs2017也不支持。比如以下显示百分比,精确到小数点后一位, 原本期望的值是50.0%. 但是wsprintf得到的值是f%
auto number = 50.000000f;
wchar_t buf[8] = { 0 };

wsprintf(buf, L"%.1f%%", number);
wcout << "wsprintf: " << buf << endl;
  1. Windows系统软件的是StringCbPrintf[2]格式化安全函数,它的特点:

    • 它针对内存溢出做了安全处理。
    • 它的cbDest有最大值限定.
    • 输出保证pszDest字符串一定是NULL结尾, 不会超出pszDest的范围.
  2. 所以在Windows上,如果要使用宽字节的格式化字符串,最好还是使用StringCbPrintf 系统Win32函数。

STRSAFEAPI StringCbPrintfA(
  STRSAFE_LPSTR  pszDest,
  size_t         cbDest,
  STRSAFE_LPCSTR pszFormat,
  ...            
);

例子

#include <string.h>
#include <Windows.h>
#include <Shlwapi.h>
#include <iostream>
#include <Strsafe.h>

using namespace std;

int main()
{
	auto number = 50.000000f;
	wchar_t buf[8] = { 0 };
	
	wsprintf(buf, L"%.1f%%", number);
	wcout << "wsprintf: " << buf << endl;

	StringCbPrintf(buf, sizeof(buf), L"%.1lf%%", number);
	wcout << "StringCbPrintf: " << buf << endl;

	char buf2[8] = { 0 };
	sprintf(buf2, "%.1f%%", number);
	cout << "sprintf: " << buf2 << endl;
}

输出

wsprintf: f%
StringCbPrintf: 50.0%
sprintf: 50.0%

参考

  1. wsprintf function winuser.h

  2. StringCbPrintf function strsafe.h

  3. sprintf function cppreference

以上是关于[Windows]_[C/C++]_[避免使用wsprintf函数]的主要内容,如果未能解决你的问题,请参考以下文章

在哪里下载 ws2_32.dll 2.2 版的运行函数 WSPRegisterMemory?

在 Windows 上使用 JNA 调用 __cpuid 函数

c/c++ -->自我编程风格总结

c/c++ 代码中使用sse指令集加速

Linux下C编程的学习_1

[C/C++11语法]_[初级]_[lamba 表达式介绍]