C++11 C++;仅包含std::string的变量参数
我正在尝试创建一个函数,该函数接受数量可变的std::string参数,并用它格式化字符串 例如:C++11 C++;仅包含std::string的变量参数,c++11,stdstring,variadic-functions,printf,C++11,Stdstring,Variadic Functions,Printf,我正在尝试创建一个函数,该函数接受数量可变的std::string参数,并用它格式化字符串 例如: Test::formatLine(const string::format, ...) { const std::string buffer; va_list args; va_start(args, format); vsprintf(buffer.c_str, format.c_str, args); va_end(args); cout << buffer <<
Test::formatLine(const string::format, ...)
{
const std::string buffer;
va_list args;
va_start(args, format);
vsprintf(buffer.c_str, format.c_str, args);
va_end(args);
cout << buffer << endl;
}
应该打印您好,先生代码>
t.formatLine("Hello %s %s! How %s you today?", "good", "sir", "are");
应该打印你好,好先生!你今天好吗?
甚至可以将va_list
和vsprintf
仅与std::string
一起使用,以避免char buffer[size]
工作示例(到目前为止)包含Igor建议的修复,使用缓冲区:
void Test::formatLine(string format, ...)
{
char buffer[256];
va_list args;
va_start(args, format);
vsprintf_s(buffer, format.c_str(), args);
va_end(args);
cout << buffer << endl;
}
void测试::formatLine(字符串格式,…)
{
字符缓冲区[256];
va_列表参数;
va_开始(参数,格式);
vsprintf_s(缓冲区,format.c_str(),args);
va_端(args);
首先,它是buffer.c_str()
和format.c_str()
(注意括号)
其次,vsprintf
的第一个参数应该是一个足够大的可修改缓冲区。您试图传递一个指向一个只有一个字节大的缓冲区的const char*
您可以使用vector
作为缓冲区保持器(很容易调整大小)。问题是,无法从vsprintf
中获得所需的缓冲区大小。一种方法是分配一些初始缓冲区,然后调用vsnprintf
(注意“n”)每次函数说缓冲区太小时,重复将缓冲区大小加倍。生产质量答案
#include <cstdarg>
#include <string>
#include <vector>
// requires at least C++11
const std::string vFormat(const std::string sFormat, ...) {
const char * const zcFormat = sFormat.c_str();
// initialize use of the variable argument array
va_list vaArgs;
va_start(vaArgs, sFormat);
// reliably acquire the size from a copy of
// the variable argument array
// and a functionally reliable call
// to mock the formatting
va_list vaCopy;
va_copy(vaCopy, vaArgs);
const int iLen = std::vsnprintf(NULL, 0, zcFormat, vaCopy);
va_end(vaCopy);
// return a formatted string without
// risking memory mismanagement
// and without assuming any compiler
// or platform specific behavior
std::vector<char> zc(iLen + 1);
std::vsnprintf(zc.data(), zc.size(), zcFormat, vaArgs);
va_end(vaArgs);
return std::string(zc.data(), zc.size()); }
#include <ctime>
#include <iostream>
#include <iomanip>
// demonstration of use
int main() {
std::time_t t = std::time(nullptr);
int i1 = 11; int i2 = 22; int i3 = 33;
std::cerr
<< std::put_time(std::localtime(& t), "%D %T")
<< vFormat(" [%s]: %s {i1=%d, i2=%d, i3=%d}",
"DEBUG",
"Xyz failed",
i1, i2, i3)
<< std::endl;
return 0; }
#包括
#包括
#包括
//至少需要C++11
常量std::string vFormat(常量std::string sFormat,…){
const char*const zcFormat=sFormat.c_str();
//初始化变量参数数组的使用
va_列表变量;
va_启动(vaArgs,sFormat);
//从的副本可靠地获取大小
//变量参数数组
//和功能可靠的通话
//模仿格式
va_列表vaCopy;
复印件(真空复印件、真空复印件);
const int-iLen=std::vsnprintf(NULL,0,zcopy格式);
va_end(vaCopy);
//返回带格式的字符串,不带
//内存管理不善的风险
//而且不需要任何编译器
//或特定于平台的行为
std::向量zc(iLen+1);
std::vsnprintf(zc.data(),zc.size(),zcFormat,vaArgs);
va_端(vaArgs);
返回std::string(zc.data(),zc.size());}
#包括
#包括
#包括
//使用示范
int main(){
std::time\u t=std::time(nullptr);
INTI1=11;INTI2=22;INTI3=33;
标准:cerr
只允许将普通类型传递给…
,std::string
不是这样的类型。@Xeo但他在示例中只传递普通类型:)当然,你是对的,如果你将示例更改为t.formatLine(“您好%s!”,std::string(“先生”);
你的“工作示例”只要生成的字符串可以容纳256个字符,就可以使用。此外,它使用的是Microsoft特定的、不可移植的vsprintf_s
函数;这可能是您关心的问题,也可能不是您关心的问题。为什么buf.size()+strlen(format.c_str())
?这没有任何意义。我建议您将\u TRUNCATE
作为vsnprintf\u s
的第三个参数传递。当然,如果生成的字符串长度超过256个字符,您仍然会遇到问题。出于好奇,我正在尝试将生成的字符串大小设置为动态-256应该已经足够了。不可移植的函数不是一个问题。你能给我一个在这种情况下如何使用vector的例子吗?我只是不知道如何将它与vsnprintf()一起使用。vector buf(1024);vsnprintf(&buf[0],buf.size(),format.c_str(),args)
。调整缓冲区大小留给读者作为练习。@phewvsnprint
是正确的想法,但您不必重复调用它。生成buffer
avector
并调用vsnprint(&buffer[0],0,format.c_str(),args);
。如果返回值非负,则调用buffer.resize(retval+1);
然后vsnprintf(&buffer[0],retval+1,format.c_str(),args)
@Praetorian:有趣。我刚才说,vsnprintf
如果成功返回写入的字符数,当缓冲区太小时返回-1。我现在检查了C99标准,它说vsnprintf
返回所需的缓冲区大小,因此可以用来提前测量它。我想er(但我懒得检查)MSVC实现是否不一致,或者文档是否错误。@Praetorian:另外,根据C99,如果第二个参数为0,则第一个参数可能是NULL
,因此可以执行vsnprint(NULL,0,format.c_str(),args);
。这消除了执行&buf[0]的顾虑
在零大小的向量上。此外,不应将相同的va_列表
值两次传递给两个vsnprintf
调用;每7.15p3,值在第一次调用后变得不确定。必须再次使用va_start
或事先使用va_copy
进行复制。
void Test::formatLine(string format, ...)
{
char buffer[256];
va_list args;
va_start(args, format);
vsprintf_s(buffer, format.c_str(), args);
va_end(args);
cout << buffer << endl;
}
void Test::formatLine(string format, ...)
{
vector<char> buf(256);
va_list args;
va_start(args, format);
vsnprintf_s(&buf[0], buf.size(), buf.size() + strlen(format.c_str()), format.c_str(), args);
va_end(args);
cout << &buf[0] << endl;
}
#include <cstdarg>
#include <string>
#include <vector>
// requires at least C++11
const std::string vFormat(const std::string sFormat, ...) {
const char * const zcFormat = sFormat.c_str();
// initialize use of the variable argument array
va_list vaArgs;
va_start(vaArgs, sFormat);
// reliably acquire the size from a copy of
// the variable argument array
// and a functionally reliable call
// to mock the formatting
va_list vaCopy;
va_copy(vaCopy, vaArgs);
const int iLen = std::vsnprintf(NULL, 0, zcFormat, vaCopy);
va_end(vaCopy);
// return a formatted string without
// risking memory mismanagement
// and without assuming any compiler
// or platform specific behavior
std::vector<char> zc(iLen + 1);
std::vsnprintf(zc.data(), zc.size(), zcFormat, vaArgs);
va_end(vaArgs);
return std::string(zc.data(), zc.size()); }
#include <ctime>
#include <iostream>
#include <iomanip>
// demonstration of use
int main() {
std::time_t t = std::time(nullptr);
int i1 = 11; int i2 = 22; int i3 = 33;
std::cerr
<< std::put_time(std::localtime(& t), "%D %T")
<< vFormat(" [%s]: %s {i1=%d, i2=%d, i3=%d}",
"DEBUG",
"Xyz failed",
i1, i2, i3)
<< std::endl;
return 0; }