[C/C++标准库]_[初级]_[如何实现std::string自己的Format(sprintf)函数]

场景:

1.  C语言有自己的sprintf函数,但是这个函数有个缺点,就是不知道需要创建多大的buffer, 这时候可以使用snprintf函数来计算大小,只要参数 buffer为NULL, count为0即可.

2.  这里实现std::string自己的sprintf也是用了snprintf的特性,先计算大小,再创建空间,之后存入std::string.

3.  还使用了C的可变参数特性.

std::wstring Format(const wchar_t *format,...)
{
	va_list argptr;
	va_start(argptr, format);
	int count = _vsnwprintf(NULL,0,format,argptr);
	va_end(argptr);

	va_start(argptr, format);
	wchar_t* buf = (wchar_t*)malloc(count*sizeof(wchar_t));
	_vsnwprintf(buf,count,format,argptr);
	va_end(argptr);

	std::wstring str(buf,count);
	free(buf);
	return str;
}

让我们看看可变参数的声明:

typedef char *  va_list;

#define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

#define _crt_va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _crt_va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _crt_va_end(ap)      ( ap = (va_list)0 )

注意: ap会累加,每次调用va_arg都会指向下一个参数,问题就是va_arg并不知道什么时候结束,所以如果设计其他的可变参数的函数,要先传入一个参数个数作为方法参数.

snprintf 源码实现是通过计算%的个数来判断参数个数的.

参考:

http://blog.csdn.net/echoisland/article/details/6086406

https://msdn.microsoft.com/en-us/library/1kt27hek.aspx

https://msdn.microsoft.com/en-us/library/2ts7cx93.aspx

If buffer is a null pointer and count is zero, len is returned as the count of characters required to format the output, not including the terminating null.
To make a successful call with the same argument and locale parameters, allocate a buffer holding at least len + 1 characters.

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2025-01-11 03:42:14

[C/C++标准库]_[初级]_[如何实现std::string自己的Format(sprintf)函数]的相关文章

[C/C++标准库]_[初级]_[交集和补集]

场景: 1. 计算std::vector A和 std::vector B里的相同的元素, 用于保留不删除. 2. 计算std::vector A和 std::vector B里各自的补集, 用于删除A的补集和添加B的补集,用在一些更新关联表的操作里. 比如联系人A所属分组B是一个集合BV, 把联系人A的所属分组 修改为集合CV, 就需要删除两个集合BV,CV的CV补集和新增BV补集. 3. C++标准库为我们提供了这些算法. 代码: // test_AndroidAssistant.cpp :

[C/C++标准库]_[初级]_[使用ctype里的isxxx函数时要注意的事项]

场景: 1. 标准库里的 ctype.h里的函数是用于1个字节的判断的,但是参数却是int, 这样很容易导致误用. isalpha iscntrl isdigit isgraph isprint ispunct isspace isxdigit isalnum islower isupper int isspace( int ch ); 最恶心的是vc++的实现会对超过1字节的值会直接崩溃,gcc不会!!! #if defined (_DEBUG) extern "C" int __c

[C/C++标准库]_[初级]_[使用模板删除字符串前后空格((w)string space)]

场景: 1. C++没有提供删除std::(w)string的前后空格的函数,比如TrimSpace. 2. 很多库都提供, 但是为了移植代码方便,最好还是能用标准库解决就用标准库. 下边用模板实现了移除空格的函数. test.cpp #include <iostream> #include <stdlib.h> #include <string.h> #include <string> #include <ctype.h> using name

[C/C++]_[初级]_[使用zlib库压缩文件]

场景: 1. WIndows上没找到系统提供的win32 api来生成zip压缩文件, 有知道的大牛麻烦留个言. 2. zlib比较常用,编译也方便,使用它来做压缩吧.MacOSX平台默认支持zlib库. http://zlib.net 3. zlib库里的 src\contrib\minizip\minizip.c  里有压缩例子, 我现在使用的是zlib 1.2.5,用vs2010编译完.下载地址: http://download.csdn.net/detail/infoworld/8177

[C/C++11]_[初级]_[使用正则表达式库regex]

场景 正则表达式在处理非常量字符串查找,替换时能很省事,如果稍微复杂点的字符串匹配, 没有正则表达式还真做不出来. C++11 为我们提供了正则表达式库. 使用起来比boost的正则库方便. 搞Java 的一定觉得很搞笑,这都是Java的标配功能, 怎么C++11才支持这个库,vs2010 以才支持.建议在处理字符串搜索替换时,直接用正则吧,代码量少,快速. 参考 std::regex_replace std::regex_iterator Regular Expressions (C++) 说

[Zlib]_[初级]_[使用zlib库解压提取文件]

场景: 1. zlib库跨平台,Windows和MacOSX都可以使用,还支持64位编译,轻量级,没有不用的道理. 2. 处理.zip,apk,docx文件时,因为这类文件都是zip格式,使用zlib能方便提取压缩文件里的数据. 方法: 1. 除了要使用zlib库本身,还需要使用zlib里的contrib目录minizip部分头文件和.c文件. zlib-1.2.5/src/contrib/minizip/unzip.h unzip.c,ioapi.c,ioapi.h (windows还需要 i

[libcurl]_[初级]_[使用libcurl下载大文件]

场景: 1. 在Windows编程时, 下载http页面(html,xml)可以使用winhttp库,但是并不是很下载文件,因为会失败. 由此引出了WinINet库,无奈这个库的稳定性比较低,使用例子又少, 下载大文件时经常是不完整,可查找的资料很少或者是没有特殊情况的解决办法. 2. 我的原则是如果系统有自带的就用系统的,但是 WinINet 要掌握需要花不少时间. 时间因素考虑到了libcurl. 3. libcurl支持ftp,http等协议的文件读取,还能自动获取文件大小, 最重要的是不

[C/C++不常见语法特性]_[初级]_[左值-右值-lvalue-rvalue]

参考:1. http://en.cppreference.com/w/cpp/language/value_category   << Value categories >> 2. https://msdn.microsoft.com/en-us/library/dd293668.aspx   << Rvalue Reference Declarator: && >>3. https://msdn.microsoft.com/en-us/li

[zlib]_[初级]_[使用Zlib完整解压zip内容]

场景: 1. 解压文件一般用在下载了一个zip文件之后解压,或者分析某个文件需要解压的操作上. 2. 解压文件,特别是解压带文件夹的zip文件往往系统没有提供这类Win32 API,当然C#自带库能解压, 当然这里只讨论C/C++, 像C#和Java这种开挂的标准库不在考虑范围内. 3. zlib解压文件的使用例子在 contrib\minizip 例子里. 这里基本是直接提取miniunz.c 的代码进行封装解压即可, 只是改了下支持中文路径. 主文件 zip_util.cpp #includ