我必须用sprintf格式化std::string,并将其发送到文件流。我该怎么做呢?
当前回答
Poco Foundation库有一个非常方便的格式函数,它在格式字符串和值中都支持std::string:
道格:http://pocoproject.org/docs/Poco.html # 7308 来源:https://github.com/pocoproject/poco/blob/develop/Foundation/src/Format.cpp
其他回答
你不能直接这样做,因为你没有对底层缓冲区的写访问权(直到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();
我对这个非常流行的问题的看法。
引用printf类函数的manpage:
Upon successful return, these functions return the number of characters printed (excluding the null byte used to end output to strings). The functions snprintf() and vsnprintf() do not write more than size bytes (including the terminating null byte ('\0')). If the output was truncated due to this limit then the return value is the number of characters (excluding the terminating null byte) which would have been written to the final string if enough space had been available. Thus, a return value of size or more means that the output was truncated.
换句话说,一个正常的c++ 11实现应该是这样的:
#include <string>
#include <cstdio>
template <typename... Ts>
std::string fmt (const std::string &fmt, Ts... vs)
{
char b;
size_t required = std::snprintf(&b, 0, fmt.c_str(), vs...) + 1;
// See comments: the +1 is necessary, while the first parameter
// can also be set to nullptr
char bytes[required];
std::snprintf(bytes, required, fmt.c_str(), vs...);
return std::string(bytes);
}
它工作得很好:)
只有c++ 11支持可变参数模板。pixelpoint的答案显示了使用较旧的编程风格的类似技术。
奇怪的是,c++没有这样一个开箱即用的东西。他们最近添加了to_string(),在我看来这是向前迈出的一大步。我想知道他们是否最终会给std::string添加一个.format操作符…
Edit
正如alexk7指出的那样,std::snprintf的返回值需要A +1,因为我们需要为\0字节留出空间。直观地说,在大多数体系结构上,缺少+1将导致所需的整数部分被0覆盖。这将在std::snprintf的required作为实际参数计算之后发生,因此效果不应该可见。
然而,这个问题可以改变,例如编译器优化:如果编译器决定为所需的变量使用寄存器怎么办?这类错误有时会导致安全问题。
我现在将为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
这是一个特定于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 );
template<typename... Args>
std::string string_format(const char* fmt, Args... args)
{
size_t size = snprintf(nullptr, 0, fmt, args...);
std::string buf;
buf.reserve(size + 1);
buf.resize(size);
snprintf(&buf[0], size + 1, fmt, args...);
return buf;
}
使用C99 snprintf和c++ 11
推荐文章
- 为什么我的程序不能在Windows 7下用法语编译?
- 是否有可能更新一个本地化的故事板的字符串?
- 为什么字符串类型的默认值是null而不是空字符串?
- 如何获取变量的类型?
- 什么是奇怪的重复模板模式(CRTP)?
- 在Python中包装长行
- 连接两个向量的最佳方法是什么?
- 在Windows批处理脚本中格式化日期和时间
- 在c++中,是通过值传递更好,还是通过引用到const传递更好?
- string. isnullorempty (string) vs. string. isnullowhitespace (string)
- 在STL中deque到底是什么?
- 如何检查字符串的特定字符?
- 在Android中设置TextView span的颜色
- Haskell:将Int转换为字符串
- Windows上最好的免费c++分析器是什么?