我正在使用一个用C++实现的开源UNIX工具,我需要修改一些代码才能让它实现我想要的功能。我想做最小的改变,希望我的补丁能在上游被接受。可以在标准C++中实现并且不会创建更多外部依赖项的解决方案是首选。
这就是我的问题。我有一个C++类--让我们称它为"A“--它目前使用fprintf()将其高度格式化的数据结构打印到文件指针。在它的print函数中,它还递归地调用几个成员类的相同定义的print函数("B“是一个例子)。还有另一个类C,它的成员std::string "foo“需要设置为A的实例的print()结果。可以将它看作A的to_str()成员函数。
在伪代码中:
class A {
public:
...
void print(FILE* f);
B b;
...
};
...
void A::print(FILE *f)
{
std::string s = "stuff";
fprintf(f, "some %s", s);
b.print(f);
}
class C {
...
std::string foo;
bool set_foo(std::str);
...
}
...
A a = new A();
C c = new C();
...
// wish i knew how to write A's to_str()
c.set_foo(a.to_str());
值得一提的是,C是相当稳定的,但A和B(以及A的其余依赖项)处于不断变化的状态,因此需要的代码更改越少越好。还需要保留当前的打印(FILE* F)接口。我考虑了几种实现A::to_str()的方法,每种方法都有优缺点:
- I wouldn't have to rewrite any format strings
- print() could be reimplemented as: fprint(f, this.to\_str());
- But I would need to manually allocate char[]s, merge a lot of c strings , and finally convert the character array to a std::string
中捕获a.print()的结果
- I would have to convert all of the format strings to << output format. There are hundreds of fprintf()s to convert :-{
- print() would have to be rewritten because there is no standard way that I know of to create an output stream from a UNIX file handle (though [this guy says it may be possible](http://synflood.at/blog/index.php?/archives/456-One-word-of-warning-about-stdio_filebuf.html)).
使用Boost的字符串format library的
- More external dependencies. Yuck.
- Format's syntax is different enough from printf() to be annoying:
printf(format_str,args) -> cout << boost::format(format_str) % arg1 % arg2 %等
使用Qt的QString::asprintf()的
- A different external dependency.
那么,我是否已经用尽了所有可能的选择?如果是这样,你认为哪一个是我最好的选择?如果不是,我忽略了什么?
谢谢。
发布于 2008-09-16 06:18:26
我使用的是#3: boost字符串格式库--但我必须承认,我从来没有在格式规范方面遇到过任何问题。
对我来说工作起来很棒--而外部依赖关系可能更糟(一个非常稳定的库)
已编辑:添加如何使用boost::format而不是printf的示例:
sprintf(buffer, "This is a string with some %s and %d numbers", "strings", 42);
在boost::format库中应该是这样的:
string = boost::str(boost::format("This is a string with some %s and %d numbers") %"strings" %42);
我希望这有助于阐明boost::format的用法
我在4到5个应用程序中使用过boost::format作为sprintf / printf的替代品(将格式化字符串写入文件,或将自定义输出写入日志文件),并且从未遇到过格式差异问题。可能有一些(或多或少模糊的)格式说明符是不同的-但我从来没有遇到过问题。
相比之下,我有一些流不能真正做到的格式规范(就我所记得的那样)
发布于 2008-09-16 06:52:14
这是我喜欢的一个习惯用法,用来使功能与“sprintf”相同,但返回一个std::string,并且不会出现缓冲区溢出问题。这段代码是我正在编写的一个开源项目(BSD许可)的一部分,所以每个人都可以随意使用它。
#include <string>
#include <cstdarg>
#include <vector>
#include <string>
std::string
format (const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
std::string buf = vformat (fmt, ap);
va_end (ap);
return buf;
}
std::string
vformat (const char *fmt, va_list ap)
{
// Allocate a buffer on the stack that's big enough for us almost
// all the time.
size_t size = 1024;
char buf[size];
// Try to vsnprintf into our buffer.
va_list apcopy;
va_copy (apcopy, ap);
int needed = vsnprintf (&buf[0], size, fmt, ap);
// NB. On Windows, vsnprintf returns -1 if the string didn't fit the
// buffer. On Linux & OSX, it returns the length it would have needed.
if (needed <= size && needed >= 0) {
// It fit fine the first time, we're done.
return std::string (&buf[0]);
} else {
// vsnprintf reported that it wanted to write more characters
// than we allotted. So do a malloc of the right size and try again.
// This doesn't happen very often if we chose our initial size
// well.
std::vector <char> buf;
size = needed;
buf.resize (size);
needed = vsnprintf (&buf[0], size, fmt, apcopy);
return std::string (&buf[0]);
}
}
编辑:当我写这段代码时,我不知道这需要C99一致性,并且Windows (以及更老的glibc)有不同的vsnprintf行为,当失败时,它返回-1,而不是确定需要多少空间。这是我修改过的代码,请大家看一看,如果你觉得没问题,我会重新编辑,使其成为唯一列出的成本:
std::string
Strutil::vformat (const char *fmt, va_list ap)
{
// Allocate a buffer on the stack that's big enough for us almost
// all the time. Be prepared to allocate dynamically if it doesn't fit.
size_t size = 1024;
char stackbuf[1024];
std::vector<char> dynamicbuf;
char *buf = &stackbuf[0];
va_list ap_copy;
while (1) {
// Try to vsnprintf into our buffer.
va_copy(ap_copy, ap);
int needed = vsnprintf (buf, size, fmt, ap);
va_end(ap_copy);
// NB. C99 (which modern Linux and OS X follow) says vsnprintf
// failure returns the length it would have needed. But older
// glibc and current Windows return -1 for failure, i.e., not
// telling us how much was needed.
if (needed <= (int)size && needed >= 0) {
// It fit fine so we're done.
return std::string (buf, (size_t) needed);
}
// vsnprintf reported that it wanted to write more characters
// than we allotted. So try again using a dynamic buffer. This
// doesn't happen very often if we chose our initial size well.
size = (needed > 0) ? (needed+1) : (size*2);
dynamicbuf.resize (size);
buf = &dynamicbuf[0];
}
}
发布于 2008-09-16 06:19:00
可以将std::string和iostream与格式一起使用,例如在iomanip中使用setw()调用和其他方法
https://stackoverflow.com/questions/69738
复制相似问题