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


当前回答

_return.desc = (boost::format("fail to detect. cv_result = %d") % st_result).str();

其他回答

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);
}

这是谷歌的做法: facebook也以类似的方式:StringPrintf (Apache许可证) 两者都提供了一个方便的StringAppendF。

c++ 20有std::format,它在API方面类似于sprintf,但完全是类型安全的,适用于用户定义的类型,并使用类似python的格式字符串语法。下面是如何格式化std::string并将其写入流的方法:

std::string s = "foo";
std::cout << std::format("Look, a string: {}", s);

或者,你可以使用{fmt}库格式化字符串,并将其写入标准输出或文件流:

fmt::print("Look, a string: {}", s);

至于sprintf或这里的大多数其他答案,不幸的是,它们使用了可变参数,并且本质上是不安全的,除非您使用类似GCC的format属性,它只适用于文字格式字符串。你可以在下面的例子中看到为什么这些函数是不安全的:

std::string format_str = "%s";
string_format(format_str, format_str[0]);

其中string_format是Erik Aronesty的答案的实现。这段代码可以编译,但是当你试图运行它时,它很可能会崩溃:

$ g++ -Wall -Wextra -pedantic test.cc 
$ ./a.out 
Segmentation fault: 11

免责声明:我是{fmt}和c++ 20 std::format的作者。

以下是我的(简单的解决方案):

std::string Format(const char* lpszFormat, ...)
{
    // Warning : "vsnprintf" crashes with an access violation
    // exception if lpszFormat is not a "const char*" (for example, const string&)

    size_t  nSize     = 1024;
    char    *lpBuffer = (char*)malloc(nSize);

    va_list lpParams;

    while (true)
    {
        va_start(lpParams, lpszFormat);

        int nResult = vsnprintf(
            lpBuffer,
            nSize,
            lpszFormat,
            lpParams
        );

        va_end(lpParams);

        if ((nResult >= 0) && (nResult < (int)nSize) )
        {
            // Success

            lpBuffer[nResult] = '\0';
            std::string sResult(lpBuffer);

            free (lpBuffer);

            return sResult;
        }
        else
        {
            // Increase buffer

            nSize =
                  (nResult < 0)
                ? nSize *= 2
                : (nResult + 1)
            ;

            lpBuffer = (char *)realloc(lpBuffer, nSize);
        }
    }
}

这个问题已经解决了。但是,我认为这是c++中格式化字符串的另一种方式

class string_format {
private:
    std::string _result;
public:
    string_format( ) { }
    ~string_format( ) { std::string( ).swap( _result ); }
    const std::string& get_data( ) const { return _result; }
    template<typename T, typename... Targs>
    void format( const char* fmt, T value, Targs... Fargs ) {
        for ( ; *fmt != '\0'; fmt++ ) {
            if ( *fmt == '%' ) {
                _result += value;
                this->format( fmt + 1, Fargs..., 0 ); // recursive call
                return;
            }
            _result += *fmt;
        }
    }
    friend std::ostream& operator<<( std::ostream& ostream, const string_format& inst );
};
inline std::string& operator+=( std::string& str, int val ) {
    str.append( std::to_string( val ) );
    return str;
}
inline std::string& operator+=( std::string& str, double val ) {
    str.append( std::to_string( val ) );
    return str;
}
inline std::string& operator+=( std::string& str, bool val ) {
    str.append( val ? "true" : "false" );
    return str;
}
inline std::ostream& operator<<( std::ostream& ostream, const string_format& inst ) {
    ostream << inst.get_data( );
    return ostream;
}

并测试这个类:

string_format fmt;
fmt.format( "Hello % and is working ? Ans: %", "world", true );
std::cout << fmt;

你可以在这里查一下