Eon*_*nil 29 c++ formatting printf ostream
我正在学习C++.cout是一个std::ostream类的实例.如何用它打印格式化的字符串?
我仍然可以使用printf,但我想学习更多C++风格的方法,它可以带来所有C++的好处.我认为这应该是可能的,std::ostream但我找不到合适的方法.
jog*_*pan 32
您可以std::ostream直接做的唯一事情是众所周知的<<-syntax:
int i = 0;
std::cout << "this is a number: " << i;
Run Code Online (Sandbox Code Playgroud)
并且有各种IO操纵器可用于影响整数,浮点数等的格式,位数等.
但是,这与格式化的字符串不同printf.C++ 11不包含任何允许您以与使用它相同的方式使用字符串格式的工具printf(除了printf本身,如果您愿意,您当然可以在C++中使用它).
在提供printf样式功能的库方面boost::format,可以实现这样的代码(从概要中复制):
std::cout << boost::format("writing %1%, x=%2% : %3%-th try") % "toto" % 40.23 % 50;
Run Code Online (Sandbox Code Playgroud)
还要注意的是有一个列入提议的printf在标准的未来版本样式的格式.如果这被接受,则可能会出现以下语法:
std::cout << std::putf("this is a number: %d\n",i);
Run Code Online (Sandbox Code Playgroud)
vit*_*aut 15
在 C++20 中,您将能够使用类似std::format安全printf的格式:
std::cout << std::format("The answer is {}.\n", 42);
Run Code Online (Sandbox Code Playgroud)
除了该{} FMT库,std::format是基于,提供了print结合的格式化和输出功能:
fmt::print("The answer is {}.\n", 42);
Run Code Online (Sandbox Code Playgroud)
免责声明:我是 {fmt} 和 C++20 的作者std::format。
小智 11
这是我已经习惯的成语。希望它有帮助:
// Hacky but idiomatic printf style syntax with c++ <<
#include <cstdlib> // for sprintf
char buf[1024]; sprintf(buf, "%d score and %d years ago", 4, 7);
cout << string(buf) <<endl;
Run Code Online (Sandbox Code Playgroud)
&
我建议使用 ostringstream 而不是 ostream 参见以下示例:
#include <vector>
#include <string>
#include <iostream>
#include "CppUnitTest.h"
#define _CRT_NO_VA_START_VALIDATION
std::string format(const std::string& format, ...)
{
va_list args;
va_start(args, format);
size_t len = std::vsnprintf(NULL, 0, format.c_str(), args);
va_end(args);
std::vector<char> vec(len + 1);
va_start(args, format);
std::vsnprintf(&vec[0], len + 1, format.c_str(), args);
va_end(args);
return &vec[0];
}
Run Code Online (Sandbox Code Playgroud)
用法示例:
std::ostringstream ss;
ss << format("%s => %d", "Version", Version) << std::endl;
Logger::WriteMessage(ss.str().c_str()); // write to unit test output
std::cout << ss.str() << std::endl; // write to standard output
Run Code Online (Sandbox Code Playgroud)
要实现 printf 可以使用 c++11 模板参数:
#include <iostream>
#include <string>
inline std::ostream & mprintf(std::ostream & ostr, const char * fstr) throw()
{
return ostr << fstr;
}
template<typename T, typename... Args>
std::ostream & mprintf(std::ostream & ostr,
const char * fstr, const T & x) throw()
{
size_t i=0;
char c = fstr[0];
while (c != '%')
{
if(c == 0) return ostr; // string is finished
ostr << c;
c = fstr[++i];
};
c = fstr[++i];
ostr << x;
if(c==0) return ostr; //
// print the rest of the stirng
ostr << &fstr[++i];
return ostr;
}
template<typename T, typename... Args>
std::ostream & mprintf(std::ostream & ostr,
const char * fstr, const T & x, Args... args) throw()
{
size_t i=0;
char c = fstr[0];
while (c != '%')
{
if(c == 0) return ostr; // string is finished
ostr << c;
c = fstr[++i];
};
c = fstr[++i];
ostr << x;
if(c==0) return ostr; // string is finished
return mprintf(ostr, &fstr[++i], args...);
}
int main()
{
int c = 50*6;
double a = 34./67.;
std::string q = "Hello!";
// put only two arguments
// the symbol after % does not matter at all
mprintf(std::cout, "%f + %f = %a \n", c, a);
// print string object: for real printf one should write q.c_str()
mprintf(std::cout, "message: \"%s\". \n", q);
// the last argument will be ignored
mprintf(std::cout, "%z + %f\n", (long)a, 12, 544 );
}
Run Code Online (Sandbox Code Playgroud)
输出
300 + 2 = %a
message: "Hello!".
2 + 12
Run Code Online (Sandbox Code Playgroud)
这是一个非常简单的代码,可以改进。
1)优点是它使用<<将对象打印到流,因此您可以放置可以通过<<输出的任意参数。
2) 它忽略格式化字符串中参数的类型:在 % 之后可以代表任意符号,甚至是空格。输出流决定如何打印相应的对象。它还与 printf 兼容。
3)缺点是不能打印百分号'%',需要稍微改进一下代码。
4) 它不能打印格式化的数字,如 %4.5f
5) 如果参数数量少于格式化字符串预测的数量,则该函数只打印字符串的其余部分。
6) 如果参数数量大于格式化字符串预测的数量,则忽略剩余的参数
可以改进代码使 2)-6) 完全模仿 printf 行为。但是,如果您遵循 printf 的规则,那么基本上只需要修复 3) 和 4)。