我必须用sprintf格式化std::string,并将其发送到文件流。我该怎么做呢?


当前回答

可以使用iomanip头文件格式化cout中的c++输出。 在使用类似的任何helper函数之前,请确保包含iomanip头文件 Setprecision, setfill等等。

下面是我过去用来在向量中打印平均等待时间的代码片段,这是我“累积”的。

#include<iomanip>
#include<iostream>
#include<vector>
#include<numeric>

...

cout<< "Average waiting times for tasks is " << setprecision(4) << accumulate(all(waitingTimes), 0)/double(waitingTimes.size()) ;
cout << " and " << Q.size() << " tasks remaining" << endl;

下面是如何格式化c++流的简要描述。 http://www.cprogramming.com/tutorial/iomanip.html

其他回答

c++ 11内部使用vsnprintf()的解决方案:

#include <stdarg.h>  // For va_start, etc.

std::string string_format(const std::string fmt, ...) {
    int size = ((int)fmt.size()) * 2 + 50;   // Use a rubric appropriate for your code
    std::string str;
    va_list ap;
    while (1) {     // Maximum two passes on a POSIX system...
        str.resize(size);
        va_start(ap, fmt);
        int n = vsnprintf((char *)str.data(), size, fmt.c_str(), ap);
        va_end(ap);
        if (n > -1 && n < size) {  // Everything worked
            str.resize(n);
            return str;
        }
        if (n > -1)  // Needed size returned
            size = n + 1;   // For null char
        else
            size *= 2;      // Guess at a larger size (OS specific)
    }
    return str;
}

一种更安全、更有效的方法(我测试过,它更快):

#include <stdarg.h>  // For va_start, etc.
#include <memory>    // For std::unique_ptr

std::string string_format(const std::string fmt_str, ...) {
    int final_n, n = ((int)fmt_str.size()) * 2; /* Reserve two times as much as the length of the fmt_str */
    std::unique_ptr<char[]> formatted;
    va_list ap;
    while(1) {
        formatted.reset(new char[n]); /* Wrap the plain char array into the unique_ptr */
        strcpy(&formatted[0], fmt_str.c_str());
        va_start(ap, fmt_str);
        final_n = vsnprintf(&formatted[0], n, fmt_str.c_str(), ap);
        va_end(ap);
        if (final_n < 0 || final_n >= n)
            n += abs(final_n - n + 1);
        else
            break;
    }
    return std::string(formatted.get());
}

fmt_str是按值传递的,以符合va_start的要求。

注意:“更安全”和“更快”的版本在某些系统上不起作用。因此,两家公司仍在上市。此外,“更快”完全取决于预分配步骤是否正确,否则strcpy会使其变慢。

你不能直接这样做,因为你没有对底层缓冲区的写访问权(直到c++ 11;见Dietrich Epp的评论)。你必须先在c-string中执行,然后将其复制到std::string中:

  char buff[100];
  snprintf(buff, sizeof(buff), "%s", "Hello");
  std::string buffAsStdStr = buff;

但我不确定为什么不直接使用字符串流?我想你有特定的理由不这么做:

  std::ostringstream stringStream;
  stringStream << "Hello";
  std::string copyOfStr = stringStream.str();

根据Erik Aronesty提供的答案:

std::string string_format(const std::string &fmt, ...) {
    std::vector<char> str(100,'\0');
    va_list ap;
    while (1) {
        va_start(ap, fmt);
        auto n = vsnprintf(str.data(), str.size(), fmt.c_str(), ap);
        va_end(ap);
        if ((n > -1) && (size_t(n) < str.size())) {
            return str.data();
        }
        if (n > -1)
            str.resize( n + 1 );
        else
            str.resize( str.size() * 2);
    }
    return str.data();
}

这避免了需要从原始答案中的.c_str()结果中取消const。

这是一个特定于Windows的解决方案,旨在避免Visual Studio中的编译器警告而不消除它们。所讨论的警告是针对使用std::string和va_start,这会错误地产生警告,以及针对使用已弃用的printf变量。

template<typename ... va>
std::string Format( const std::string& format, va ... args )
{
    std::string s;
    s.resize( _scprintf( format.c_str(), args ... ) + 1 );
    s.resize( _snprintf_s( s.data(), s.capacity(), _TRUNCATE, format.c_str(), args ... ) );
    return s;
}

template<typename ... va>
std::wstring Format( const std::wstring& format, va ... args )
{
    std::wstring s;
    s.resize( _scwprintf( format.c_str(), args ... ) + 1 );
    s.resize( _snwprintf_s( s.data(), s.capacity(), _TRUNCATE, format.c_str(), args ... ) );
    return s;
}

std::string s = Format( "%hs %d", "abc", 123 );
std::wstring ws = Format( L"%hs %d", "abc", 123 );

我现在将为Visual Studio编写版本,希望有一天有人会让它变得可移植。(怀疑需要用vsnwprintf替换_vsnwprintf之类的东西。)

您需要使用项目配置中的define _CRT_SECURE_NO_WARNINGS来禁用已弃用的警告。

我使用_vsnwprintf与第一个参数作为nullptr能够估计缓冲区大小,保留wstring缓冲区,然后格式化字符串直接到缓冲区。

不确定为什么需要禁用已弃用警告,因为相同方法调用(_vsnwprintf_s)的安全版本不能使用nullptr作为输入。怀疑需要报告给微软c++团队。

这个版本应该同时使用- string类或wstring类。

如果你发现任何错误或不一致,请再问一次,我会尽力修复它。

stringHelpers.h:

#pragma once
#include <string>

//
//  Formats string/wstring according to format, if formatting fails (e.g. invalid %s pointer - returns empty string)
//
template <typename T>
std::basic_string<T> sFormat(const T* format, ...)
{
    va_list args;
    va_start(args, format);
    int size;

    if constexpr (std::is_same_v<T, char>)
        size = vsnprintf(nullptr, 0, format, args);
    else
        size = _vsnwprintf(nullptr, 0, format, args);

    size++; // Zero termination
    std::basic_string<T> s;
    s.resize(size);

    if constexpr (std::is_same_v<T, char>)
        vsnprintf(&s[0], size, format, args);
    else
        _vsnwprintf(&s[0], size, format, args);

    va_end(args);
    return s;
}

以上是代码示例,可以复制。我将维护工作版本在我自己的仓库在github:

https://github.com/tapika/cppscriptcore/blob/master/SolutionProjectModel/helpers.h#L12