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


当前回答

inline void format(string& a_string, const char* fmt, ...)
{
    va_list vl;
    va_start(vl, fmt);
    int size = _vscprintf( fmt, vl );
    a_string.resize( ++size );
    vsnprintf_s((char*)a_string.data(), size, _TRUNCATE, fmt, vl);
    va_end(vl);
}

其他回答

String没有你需要的东西,但是std::stringstream有。使用stringstream创建字符串,然后提取字符串。这里有一个关于你可以做的事情的全面列表。例如:

cout.setprecision(10); //stringstream is a stream like cout

将在打印双精度或浮点数时提供10位小数点后的精度。

这是一个特定于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 );

我不喜欢把事情搞复杂。这是基于iFreilicht的答案,但我减少了一些噪音,使它更有效。请注意,如果您计划在接口中使用此功能,可能会添加一些模糊输入检查。

#include <iostream>
#include <string>

template<typename... Ts>
std::string string_format( const std::string& format, Ts... Args )
{
    const size_t n = std::snprintf( nullptr, 0, format.c_str(), Args ... ) + 1; // Extra space for '\0'
    std::string ret(n, '\0');
    std::snprintf( &ret.front(), n, format.c_str(), Args... );
    return ret;
}

int main()
{
    int a = 5;
    char c = 'h';
    double k = 10.3;
    std::cout << string_format("%d, %c, %.2f", a, c, k) << "\n";
}

输出:

5, h, 10.30

试着自己

(*唯一的警告,我发现性能方面是没有办法默认初始化字符串存储。这很遗憾,因为我们不需要在这里将所有的值初始化为“\0”。)

c++ 20 std::格式

它来了!该特性描述在:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0645r9.html,并使用类似python的.format()语法。

我希望它的用法是这样的:

#include <format>
#include <string>

int main() {
    std::string message = std::format("The answer is {}.", 42);
}

g++-9 -std=c++2a的GCC 9.1.0仍然不支持它。

现有的fmt库在获得官方支持之前实现了它:https://github.com/fmtlib/fmt,如前所述:std::string格式化,如sprintf:

sudo apt install libfmt-dev

修改源代码以替换:

用<fmt/core.h> .h格式化> Std::format转换为fmt::format

main.cpp

#include <string>
#include <iostream>

#include <fmt/core.h>

int main() {
    std::string message = fmt::format("The answer is {}.", 42);
    std::cout << message << std::endl;
}

编译并运行:

g++ -std=c++11 -o main.out main.cpp -lfmt
./main.out

输出:

The answer is 42.

API将添加一个新的std::format头文件:

建议的格式化API定义在新的header <format>中,应该不会对现有代码产生影响。

十六进制格式{:x}

c++十六进制成本值?

前导零{:03}

用c++输出操作符打印前导零?

左对齐{:<},右对齐{:>},中对齐{:^}

打印cout时c++对齐<<

浮点精度{:.2}

我如何打印一个双值与全精度使用cout? 在c++中设置默认浮点打印精度

在正数{:+}上显示符号

如何打印正数与前缀+在c++

将布尔值显示为true和false: {:}

在c++中将bool转换为文本

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会使其变慢。