我在C ++ 11中使用sprintf
函数,方法如下:
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;
}
有没有比这更好的方法来检查每次保留的空间是否足够?为了将来添加更多东西的可能性。
答案 0 :(得分:14)
您的构造 - 写入到从c_str()
收到的缓冲区 - 是未定义的行为,即使您事先检查了字符串的容量。 (返回值是指向 const char的指针,函数本身标记为 const ,原因。)
不要将C和C ++,特别是混合在一起,而不是写入内部对象表示。 (这打破了非常基本的OOP。)使用C ++,类型安全,不会遇到转换说明符/参数不匹配,如果没有别的。
std::ostringstream s;
s << "Type=" << INDEX_RECORD_TYPE_SERIALIZATION_HEADER
<< " Version=" << FORMAT_VERSION
// ...and so on...
;
std::string output = s.str();
替代:
std::string output = "Type=" + std::to_string( INDEX_RECORD_TYPE_SERIALIZATION_HEADER )
+ " Version=" + std::to_string( FORMAT_VERSION )
// ...and so on...
;
答案 1 :(得分:8)
其他答案中显示的C ++模式更好,但为了完整性,这是sprintf
的正确方法:
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
。std::string
缓冲区在C ++ 11之前并不保证是连续的,这依赖于该保证。如果您需要支持使用std::string
的绳索实现的异乎寻常的C ++ 11前符合平台,那么您最好先将冲刺转移到std::vector<char>
然后再复制字符串的向量。答案 2 :(得分:1)
你的代码错了。 reserve
为字符串分配内存,但不会更改其大小。写入c_str
返回的缓冲区也不会改变其大小。所以字符串仍然认为它的大小是0,你只是在字符串缓冲区的未使用空间中写了一些东西。 (可能。从技术上讲,代码具有未定义的行为,因为写入c_str
是未定义的,因此任何事情都可能发生。)
你真正想做的是忘记sprintf
和类似的C风格函数,并使用C ++方式的字符串格式化 - 字符串流:
std::ostringstream ss;
ss << "Type=" << INDEX_RECORD_TYPE_SERIALIZATION_HEADER
<< " Version=" << FORAMT_VERSION
<< /* ... the rest ... */;
return ss.str();
答案 3 :(得分:1)
更好的方法是使用{fmt} library。例如:
std::string message = fmt::sprintf("The answer is %d", 42);
它还提供了比iostreams和printf更好的界面。例如:
std::string message = fmt::format("The answer is {}", 42);`
请参阅:
https://github.com/fmtlib/fmt
http://fmtlib.net/latest/api.html#printf-formatting-functions
答案 4 :(得分:1)
我们可以混合来自https://stackoverflow.com/a/36909699/2667451和https://stackoverflow.com/a/7257307的代码,结果将是这样的:
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;
}
答案 5 :(得分:0)
是的,有!
在C中,更好的方法是将文件与 null 设备相关联,并为其创建所需输出的虚拟request.Headers.Authorization.Parameter = "VXNlcjpQYXNzd29yZA=="
,以了解如果需要多少空间,实际打印。然后为其分配适当的缓冲区和printf
相同的数据。
在C ++中,您也可以将输出流与空设备相关联,并测试使用std::ostream::tellp打印的字符数。但是,使用sprintf
是一种更好的解决方案 - 请参阅DevSolar或Angew的答案。