Using sprintf with std::string in C++
我通过以下方式在C ++ 11中使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | std::string toString() { std::string output; uint32_t strSize=512; do { output.reserve(strSize); int ret = sprintf(output.c_str(),"Type=%u Version=%u ContentType=%u contentFormatVersion=%u magic=%04x Seg=%u", INDEX_RECORD_TYPE_SERIALIZATION_HEADER, FORAMT_VERSION, contentType, contentFormatVersion, magic, segmentId); strSize *= 2; } while (ret < 0); return output; } |
有没有比每次检查预留空间是否足够的方法更好的方法了? 为了将来添加更多东西的可能性。
即使事先检查了字符串的容量,您的构造(写入从
不要混合使用C和C ++,尤其是不要用于编写内部对象表示形式。 (这打破了最基本的OOP。)使用C ++可以确保类型安全,并且不会遇到转换说明符/参数不匹配的情况(如果没有其他原因)。
1 2 3 4 5 6 | std::ostringstream s; s <<"Type=" << INDEX_RECORD_TYPE_SERIALIZATION_HEADER <<" Version=" << FORMAT_VERSION // ...and so on... ; std::string output = s.str(); |
选择:
1 2 3 4 | std::string output ="Type=" + std::to_string( INDEX_RECORD_TYPE_SERIALIZATION_HEADER ) +" Version=" + std::to_string( FORMAT_VERSION ) // ...and so on... ; |
其他答案中显示的C ++模式更好,但是出于完整性考虑,这是
1 2 3 4 | auto format ="your %x format %d string %s"; auto size = std::snprintf(nullptr, 0, format /* Arguments go here*/); std::string output(size + 1, '\0'); std::sprintf(&output[0], format, /* Arguments go here*/); |
注意
-
您必须
resize 您的字符串。reserve 不会更改缓冲区的大小。在我的示例中,我直接构造了正确大小的字符串。 -
c_str() 返回const char* 。您可能无法将其传递给sprintf 。 -
在C ++ 11之前,不能保证
std::string 缓冲区是连续的,这取决于该保证。如果您需要支持使用绳索实现std::string 的特殊的C ++ 11兼容平台,那么最好先冲刺到std::vector ,然后再将向量复制到字符串中。 - 仅当未在尺寸计算和格式设置之间修改参数时,此方法才有效;对于多线程代码,请使用变量的本地副本或线程同步原语。
我们可以从这里https://stackoverflow.com/a/36909699/2667451和这里https://stackoverflow.com/a/7257307混合代码,结果将是这样的:
1 2 3 4 5 6 7 8 | template <typename ...Args> std::string stringWithFormat(const std::string& format, Args && ...args) { auto size = std::snprintf(nullptr, 0, format.c_str(), std::forward<Args>(args)...); std::string output(size + 1, '\0'); std::sprintf(&output[0], format.c_str(), std::forward<Args>(args)...); return output; } |
更好的方法是使用{fmt}库。例如:
1 | std::string message = fmt::sprintf("The answer is %d", 42); |
与iostreams和printf相比,它还提供了更好的接口。例如:
1 | std::string message = fmt::format("The answer is {}", 42);` |
看到:
https://github.com/fmtlib/fmt
http://fmtlib.net/latest/api.html#printf-formatting-functions
您的代码是错误的。
您真正想要做的是忘记
1 2 3 4 5 | std::ostringstream ss; ss <<"Type=" << INDEX_RECORD_TYPE_SERIALIZATION_HEADER <<" Version=" << FORAMT_VERSION << /* ... the rest ... */; return ss.str(); |
就在这里!
在C语言中,更好的方法是将文件与空设备关联,并向其生成所需输出的伪
在C ++中,您也可以将输出流与空设备相关联,并测试用std :: ostream :: tellp打印的字符数。但是,使用