我必须用sprintf格式化std::string,并将其发送到文件流。我该怎么做呢?
当前回答
这是我用来在我的程序中这样做的代码…这没什么特别的,但很管用……注意,您必须根据需要调整您的尺寸。我的MAX_BUFFER是1024。
std::string Format ( const char *fmt, ... )
{
char textString[MAX_BUFFER*5] = {'\0'};
// -- Empty the buffer properly to ensure no leaks.
memset(textString, '\0', sizeof(textString));
va_list args;
va_start ( args, fmt );
vsnprintf ( textString, MAX_BUFFER*5, fmt, args );
va_end ( args );
std::string retStr = textString;
return retStr;
}
其他回答
如果缓冲区不够大,无法打印字符串,就会出现问题。在打印格式化消息之前,必须确定格式化字符串的长度。 我制作了自己的帮助器(在Windows和Linux GCC上测试),您可以尝试使用它。
String.cpp: http://pastebin.com/DnfvzyKP String.h: http://pastebin.com/7U6iCUMa
String.cpp:
#include <cstdio>
#include <cstdarg>
#include <cstring>
#include <string>
using ::std::string;
#pragma warning(disable : 4996)
#ifndef va_copy
#ifdef _MSC_VER
#define va_copy(dst, src) dst=src
#elif !(__cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__))
#define va_copy(dst, src) memcpy((void*)dst, (void*)src, sizeof(*src))
#endif
#endif
///
/// \breif Format message
/// \param dst String to store formatted message
/// \param format Format of message
/// \param ap Variable argument list
///
void toString(string &dst, const char *format, va_list ap) throw() {
int length;
va_list apStrLen;
va_copy(apStrLen, ap);
length = vsnprintf(NULL, 0, format, apStrLen);
va_end(apStrLen);
if (length > 0) {
dst.resize(length);
vsnprintf((char *)dst.data(), dst.size() + 1, format, ap);
} else {
dst = "Format error! format: ";
dst.append(format);
}
}
///
/// \breif Format message
/// \param dst String to store formatted message
/// \param format Format of message
/// \param ... Variable argument list
///
void toString(string &dst, const char *format, ...) throw() {
va_list ap;
va_start(ap, format);
toString(dst, format, ap);
va_end(ap);
}
///
/// \breif Format message
/// \param format Format of message
/// \param ... Variable argument list
///
string toString(const char *format, ...) throw() {
string dst;
va_list ap;
va_start(ap, format);
toString(dst, format, ap);
va_end(ap);
return dst;
}
///
/// \breif Format message
/// \param format Format of message
/// \param ap Variable argument list
///
string toString(const char *format, va_list ap) throw() {
string dst;
toString(dst, format, ap);
return dst;
}
int main() {
int a = 32;
const char * str = "This works!";
string test(toString("\nSome testing: a = %d, %s\n", a, str));
printf(test.c_str());
a = 0x7fffffff;
test = toString("\nMore testing: a = %d, %s\n", a, "This works too..");
printf(test.c_str());
a = 0x80000000;
toString(test, "\nMore testing: a = %d, %s\n", a, "This way is cheaper");
printf(test.c_str());
return 0;
}
String.h:
#pragma once
#include <cstdarg>
#include <string>
using ::std::string;
///
/// \breif Format message
/// \param dst String to store formatted message
/// \param format Format of message
/// \param ap Variable argument list
///
void toString(string &dst, const char *format, va_list ap) throw();
///
/// \breif Format message
/// \param dst String to store formatted message
/// \param format Format of message
/// \param ... Variable argument list
///
void toString(string &dst, const char *format, ...) throw();
///
/// \breif Format message
/// \param format Format of message
/// \param ... Variable argument list
///
string toString(const char *format, ...) throw();
///
/// \breif Format message
/// \param format Format of message
/// \param ap Variable argument list
///
string toString(const char *format, va_list ap) throw();
可以使用iomanip头文件格式化cout中的c++输出。 在使用类似的任何helper函数之前,请确保包含iomanip头文件 Setprecision, setfill等等。
下面是我过去用来在向量中打印平均等待时间的代码片段,这是我“累积”的。
#include<iomanip>
#include<iostream>
#include<vector>
#include<numeric>
...
cout<< "Average waiting times for tasks is " << setprecision(4) << accumulate(all(waitingTimes), 0)/double(waitingTimes.size()) ;
cout << " and " << Q.size() << " tasks remaining" << endl;
下面是如何格式化c++流的简要描述。 http://www.cprogramming.com/tutorial/iomanip.html
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转换为文本
这里是内存使用(和执行速度)方面的最佳解决方案,不依赖于RVO,如果字符串大小大于零,也可以执行追加,还会自动调整std::string的大小。
宏解决方案IMO更好,现代编译器将警告如果格式字符串不匹配的类型。该函数版本不会出现此警告,因为编译器无法看到snprintf。宏版本也更短,它也需要一个更少的包含。
来自:
https://github.com/ericcurtin/twincam
宏观的解决方案:
#include <string.h>
#include <string>
// function that will sprintf to a C++ string starting from std::string::size()
// so if you want to completely overwrite a string or start at a specific point
// use std::string::clear() or std::string::resize(). str is a std::string.
#define STRING_PRINTF(str, ...) \
do { \
const int size = snprintf(NULL, 0, __VA_ARGS__); \
const size_t start_of_string = str.size(); \
str.resize(start_of_string + size); \
snprintf(&str[start_of_string], str.size() + 1, __VA_ARGS__); \
} while (0)
函数的解决方案:
#include <stdarg.h> // For va_start, etc.
#include <string.h>
#include <string>
// function that will sprintf to a C++ string starting from std::string::size()
// so if you want to completely overwrite a string or start at a specific point
// use std::string::clear() or std::string::resize()
int string_printf(std::string& str, const char* const fmt, ...) {
c_va_list c_args;
va_start(c_args.args, fmt);
c_va_list tmpa;
va_copy(tmpa.args, c_args.args);
// Get addtional size required
int size = vsnprintf(NULL, 0, fmt, tmpa.args);
if (size < 0) {
return -1;
}
const size_t start_of_string = str.size();
str.resize(start_of_string + size);
// plus 1 so the null terminator gets included
size = vsnprintf(&str[start_of_string], str.size() + 1, fmt, c_args.args);
return size;
}
更优解:
#define STRING_PRINTF(str, ...) \
do { \
const size_t write_point = str.size(); \
str.resize(write_point + 127); \
const int size = snprintf(&str[write_point], 128, __VA_ARGS__); \
str.resize(write_point + size); \
if (size < 128) { \
break; \
} \
\
snprintf(&str[write_point], size + 1, __VA_ARGS__); \
} while (0)
这是一个更优的解决方案,假设sprintf小于128字节,如果是,格式字符串只解析一次而不是两次。
更新了一些答案,不同的是-函数将正确接受std::string为%s
namespace format_helper
{
template <class Src>
inline Src cast(Src v)
{
return v;
}
inline const char *cast(const std::string& v)
{
return v.c_str();
}
};
template <typename... Ts>
inline std::string stringfmt (const std::string &fmt, Ts&&... vs)
{
using namespace format_helper;
char b;
size_t required = std::snprintf(&b, 0, fmt.c_str(), cast(std::forward<Ts>(vs))...);//not counting the terminating null character.
std::string result;
//because we use string as container, it adds extra 0 automatically
result.resize(required , 0);
//and snprintf will use n-1 bytes supplied
std::snprintf(const_cast<char*>(result.data()), required + 1, fmt.c_str(), cast(std::forward<Ts>(vs))...);
return result;
}
生活:http://cpp.sh/5ajsv
推荐文章
- 为什么我的程序不能在Windows 7下用法语编译?
- 是否有可能更新一个本地化的故事板的字符串?
- 为什么字符串类型的默认值是null而不是空字符串?
- 如何获取变量的类型?
- 什么是奇怪的重复模板模式(CRTP)?
- 在Python中包装长行
- 连接两个向量的最佳方法是什么?
- 在Windows批处理脚本中格式化日期和时间
- 在c++中,是通过值传递更好,还是通过引用到const传递更好?
- string. isnullorempty (string) vs. string. isnullowhitespace (string)
- 在STL中deque到底是什么?
- 如何检查字符串的特定字符?
- 在Android中设置TextView span的颜色
- Haskell:将Int转换为字符串
- Windows上最好的免费c++分析器是什么?