我正与一个开放源码的UNIX工具,是用C++实现,并且我需要改变一些代码,把它做什么我想要的。我要尽可能小的改变希望让我接受上游。解决方案可实现的标准C++并不创建更多的外部依赖性是优选的。

这里是我的问题。我有一个C++类--让我们叫它"一"--是目前使用的函数()以印刷其严格式的数据结构的一个文件指针。在其打印功能,它还递归的电话相同定义的打印功能的几个成员类("B"是一个例子)。还有另一个C类,有一个成员std::string"foo",需要设置的打印()结果的一个实例A认为它作为一个to_str()件的功能A.

在代码:

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(其余的是家属)是在一个国家的通,所以较少的代码变化所必需的更好。当前的打印(文件*F)接口也需要保护。我已经考虑了几种方法可以实现::to_str(),每个都有优点和缺点:

  1. 改变的呼吁函数()以sprintf()

    • 我不需要重写任何形式的字符串
    • print()可以重新实现为:fprint(f,这一点。to_str());
    • 但我需要手动分配char[]s,合并大量的c串,并且最后转换为字阵列标准::string
  2. 试图捕获的结果。print()中的一流串

    • 我会把所有的格式符串 << 输出格式。有数以百计的函数()s转换:-{
    • print()必须重写,因为没有标准的方式,我知道创建一个输出流从UNIX文件处理(虽然 这家伙说有可能).
  3. 使用的字符串 格式图书馆

    • 更多的外部依赖性。恶心.
    • 格式的语法是不同的足够从printf()被讨厌:

    printf(format_str,args)->状 << 加强:格式(format_str)%arg1%arg2%等等

  4. 使用夸脱的 字符串::asprintf()

    • 一个不同的外部依赖性。

所以,我用尽了所有可能的选择?如果是这样,你觉得是我最好的赌注吗?如果不是,有什么我忽略了?

谢谢。

有帮助吗?

解决方案

我使用#3:增串格式库-但我不得不承认,我从未有过任何问题存在差异的格式规格。

就像一个魅力-我和外部的依赖可能会更糟(一个非常稳定的图书馆)

编辑:增加一个例子如何使用的增强:格式,而不是printf:

sprintf(buffer, "This is a string with some %s and %d numbers", "strings", 42);

会像这样的东西用的增强:格式图书馆:

string = boost::str(boost::format("This is a string with some %s and %d numbers") %"strings" %42);

希望这有助于澄清使用的增强:格式

我已经使用的增强:格式作为一个sprintf/printf替换在4或5的应用程序(文字格式的串的文件,或者定义输出到日志),从来没有问题与格式的差异。可能有一些(或多或少的混淆)的格式说明其不同-但我从来没有一个问题。

与此相反我有一些格式规格我不能真正做到与流(尽我记得)

其他提示

这里的习语我喜欢制作功能完全相同'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];
    }
}

你可以使用std::string和iostreams用格式,如setw()电话和其他人在iomanip

以下可能是一个替代解决方案:

void A::printto(ostream outputstream) {
    char buffer[100];
    string s = "stuff";
    sprintf(buffer, "some %s", s);
    outputstream << buffer << endl;
    b.printto(outputstream);
}

(B::printto 类似的),并且定义

void A::print(FILE *f) {
    printto(ofstream(f));
}

string A::to_str() {
    ostringstream os;
    printto(os);
    return os.str();
}

当然,你真的应该使用snprintf而不是sprintf避免缓冲区溢出。你也可以选择地改变风险更大sprintfs到 << 格式,是更加安全的和未改变,尽可能少。

你应该尝试的Loki图书馆的SafeFormat头文件(http://loki-lib.sourceforge.net/index.php?n=Idioms.Printf).它是相似的,以提高字符串的格式,图书馆,但是不断的语法printf(...)的职能。

我希望这可以帮助!

这是关于化?或打印合适的?如果是前者,考虑提升::化。它是所有关于"递归"的系列化物和亚的对象。

的{fmt}图书馆 提供 fmt::sprintf 功能,执行 printf兼容的格式(包括位置参数据 POSIX说明书)和返回的结果 std::string:

std::string s = fmt::sprintf("The answer is %d.", 42);

免责声明:我是作者的这个图书馆。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top