如何使用std :: cout执行以下操作?
double my_double = 42.0;
char str[12];
printf_s("%11.6lf", my_double); // Prints " 42.000000"
我准备放弃并使用sprintf_s。
更一般地说,我在哪里可以找到std :: ostream格式的引用,它在一个地方列出所有内容,而不是在长篇教程中全部展开?
编辑2017年12月21日 - 请参阅下面的答案。它使用了我在2012年提出这个问题时无法使用的功能。
答案 0 :(得分:64)
std::cout << std::fixed << std::setw( 11 ) << std::setprecision( 6 ) << my_double;
您需要添加
#include <iomanip>
你可以用你想要的任何字符“填充”空白的地方。像这样:
std::cout << std::fixed << std::setw( 11 ) << std::setprecision( 6 )
<< std::setfill( '0' ) << my_double;
答案 1 :(得分:14)
std::cout << boost::format("%11.6f") % my_double;
您必须#include <boost\format.hpp>
答案 2 :(得分:6)
#include <iostream>
#include <iomanip>
int main() {
double my_double = 42.0;
std::cout << std::fixed << std::setw(11)
<< std::setprecision(6) << my_double << std::endl;
return 0;
}
答案 3 :(得分:6)
在C ++ 20中,您将能够做到
double my_double = 42.0;
char str[12];
std::format_to_n(str, sizeof(str), "{:11.6}", my_double);
或
std::string s = std::format("{:11.6}", my_double);
同时,您可以使用提供format_to_n
实现的the {fmt} library。
免责声明:我是{fmt}和C ++ 20 std::format
的作者。
答案 4 :(得分:5)
一般情况下,您希望避免在{。{1}}和11
中指定内容
输出点。这是物理标记,你想要逻辑标记;
例如6
或pressure
。这样,您可以在一个地方定义
如何格式化压力或体积,以及格式是否发生变化,
您不必搜索程序以找到要更改的位置
格式(并意外地改变其他东西的格式)。在
C ++,你可以通过定义一个设置各种设置的操纵器来实现
格式化选项,并最好在完整的结束时恢复它们
表达。所以你最终写的东西如下:
volume
虽然我绝对不会在生产代码中使用它,但我发现了
以下std::cout << pressure << my_double;
格式化程序对快速作业非常有用:
FFmt
这允许编写如下内容:
class FFmt : public StateSavingManip
{
public:
explicit FFmt(
int width,
int prec = 6,
std::ios::fmtflags additionalFlags
= static_cast<std::ios::fmtflags>(),
char fill = ' ' );
protected:
virtual void setState( std::ios& targetStream ) const;
private:
int myWidth;
int myPrec;
std::ios::fmtflags myFlags;
char myFill;
};
FFmt::FFmt(
int width,
int prec,
std::ios::fmtflags additionalFlags,
char fill )
: myWidth( width )
, myPrec( prec )
, myFlags( additionalFlags )
, myFill( fill )
{
myFlags &= ~ std::ios::floatfield
myFlags |= std::ios::fixed
if ( isdigit( static_cast< unsigned char >( fill ) )
&& (myFlags & std::ios::adjustfield) == 0 ) {
myFlags |= std::ios::internal
}
}
void
FFmt::setState(
std::ios& targetStream ) const
{
targetStream.flags( myFlags )
targetStream.width( myWidth )
targetStream.precision( myPrec )
targetStream.fill( myFill )
}
记录:
std::cout << FFmt( 11, 6 ) << my_double;
StateSavingManip.cc:
class StateSavingManip
{
public:
StateSavingManip(
StateSavingManip const& other );
virtual ~StateSavingManip();
void operator()( std::ios& stream ) const;
protected:
StateSavingManip();
private:
virtual void setState( std::ios& stream ) const = 0;
private:
StateSavingManip& operator=( StateSavingManip const& );
private:
mutable std::ios* myStream;
mutable std::ios::fmtflags
mySavedFlags;
mutable int mySavedPrec;
mutable char mySavedFill;
};
inline std::ostream&
operator<<(
std::ostream& out,
StateSavingManip const&
manip )
{
manip( out );
return out;
}
inline std::istream&
operator>>(
std::istream& in,
StateSavingManip const&
manip )
{
manip( in );
return in;
}
答案 5 :(得分:1)
具有完美转发的可变参数模板参数的出现使生活变得如此简单。 ostream的链式疯狂&lt;&lt;和boost :: format%可以免除。下面的函数oprintf填写账单。工作正在进行中。随意加入错误处理等等......
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <string_view>
namespace dj {
template<class Out, class... Args>
Out& oprintf(Out &out, const std::string_view &fmt, Args&&... args) {
const int sz = 512;
char buffer[sz];
int cx = snprintf(buffer, sz, fmt.data(), std::forward<Args>(args)...);
if (cx >= 0 && cx < sz) {
return out.write(buffer, cx);
} else if (cx > 0) {
// Big output
std::string buff2;
buff2.resize(cx + 1);
snprintf(buff2.data(), cx, fmt.data(), std::forward<Args>(args)...);
return out.write(buff2.data(), cx);
} else {
// Throw?
return out;
}
}
}
int main() {
const double my_double = 42.0;
dj::oprintf(std::cout, "%s %11.6lf\n", "My double ", my_double);
return 0;
}
答案 6 :(得分:1)
对于喜欢使用std :: ostream的实际printf样式格式规范的未来访问者,这是另一个变体,基于Martin York在另一个SO问题中的优秀帖子:https://stackoverflow.com/a/535636:
#include <iostream>
#include <iomanip>
#include <stdio.h> //snprintf
class FMT
{
public:
explicit FMT(const char* fmt): m_fmt(fmt) {}
private:
class fmter //actual worker class
{
public:
explicit fmter(std::ostream& strm, const FMT& fmt): m_strm(strm), m_fmt(fmt.m_fmt) {}
//output next object (any type) to stream:
template<typename TYPE>
std::ostream& operator<<(const TYPE& value)
{
// return m_strm << "FMT(" << m_fmt << "," << value << ")";
char buf[40]; //enlarge as needed
snprintf(buf, sizeof(buf), m_fmt, value);
return m_strm << buf;
}
private:
std::ostream& m_strm;
const char* m_fmt;
};
const char* m_fmt; //save fmt string for inner class
//kludge: return derived stream to allow operator overloading:
friend FMT::fmter operator<<(std::ostream& strm, const FMT& fmt)
{
return FMT::fmter(strm, fmt);
}
};
用法示例:
double my_double = 42.0;
cout << FMT("%11.6f") << my_double << "more stuff\n";
甚至:
int val = 42;
cout << val << " in hex is " << FMT(" 0x%x") << val << "\n";
答案 7 :(得分:0)
已经有了一些很好的答案;对那些人表示敬意!
这是基于其中一些。我为POD类型添加了类型断言,因为它们是printf()
可用的唯一安全类型。
#include <iostream>
#include <stdio.h>
#include <type_traits>
namespace fmt {
namespace detail {
template<typename T>
struct printf_impl
{
const char* fmt;
const T v;
printf_impl(const char* fmt, const T& v) : fmt(fmt), v(v) {}
};
template<typename T>
inline typename std::enable_if<std::is_pod<T>::value, std::ostream& >::type
operator<<(std::ostream& os, const printf_impl<T>& p)
{
char buf[40];
::snprintf(buf, sizeof(buf), p.fmt, p.v, 40);
return os << buf;
}
} // namespace detail
template<typename T>
inline typename std::enable_if<std::is_pod<T>::value, detail::printf_impl<T> >::type
printf(const char* fmt, const T& v)
{
return detail::printf_impl<T>(fmt, v);
}
} // namespace fmt
示例用法如下。
std::cout << fmt::printf("%11.6f", my_double);