[英]Using various format specifiers of c in c++
在c中,我们可以使用各种格式说明符
那么有什么办法可以将这些用于std :: cout吗?
我在课程中得到了一些负面反馈(c ++程序员的c ++),使用printf而不是cout因为我想要一些格式化:(
对于%nd
%0nd
,C ++等价物是std::setw()
和std::setfill()
。
#include <iostream> // std::cout, std::endl
#include <iomanip> // std::setfill, std::setw
int main () {
std::cout << std::setfill ('x') << std::setw (10);
std::cout << 77 << std::endl;
return 0;
}
输出: xxxxxxxx77
%.nf
可以替换为std::setprecision
%.nf
和std::fixed
,
#include <iostream> // std::cout, std::fixed, std::scientific
int main () {
double a = 3.1415926534;
double b = 2006.0;
double c = 1.0e-10;
std::cout.precision(5);
std::cout << "fixed:\n" << std::fixed;
std::cout << a << '\n' << b << '\n' << c << '\n';
return 0;
}
输出:
fixed:
3.14159
2006.00000
0.00000
C ++流不使用格式说明符,如C的printf()
类型函数; 他们使用manipulators
。
#include <iostream>
#include <iomanip>
int main()
{
std::cout << std::fixed << std::setprecision(6) << 42.0 << std::endl;
}
42.000000
C ++中通常的解决方案是定义操纵器,它指出您尝试格式化的内容,而不是直接在输出点破解物理值。 (一个可能的例外是宽度,其中std::setw
可能直接有用。)因此,例如,当实际输出某些东西时,你不会指定零填充或固定,带有2位小数,但类似于:
std::cout << temperature(2) << theTemporature;
temperature
会是这样的:
class temperature
{
int myMinWidth;
public:
temperature( int minWidth )
: myMinWidth( minWidth )
{
}
friend std::ostream& operator<<( std::ostream& dest, temperature const& manip )
{
dest.setf( std::ios_base::fixed, std::ios_base::floatfield );
dest.precision( 2 );
dest.width( myMinWidth );
return dest;
}
};
有关可用的格式修改列表,请参阅std::ios_base
的规范以及std::ios_base::fmtflags
的字段。
如果您正在进行大量输出,则可能需要修改此输出以在完整表达式的末尾恢复原始格式标志。 (除了宽度之外的所有格式信息都是粘性的,因此强制使用固定格式会使您的程序的其余部分保持固定格式,这不一定是您想要的。)我使用以下作为所有我的基类机械手:
class StateSavingManip
{
public:
void operator()( std::ios& stream ) const;
protected:
StateSavingManip() : myStream( nullptr ) {}
~StateSavingManip();
private:
virtual void setState( std::ios& stream ) const = 0;
private:
mutable std::ios* myStream;
mutable std::ios::fmtflags mySavedFlags;
mutable int mySavedPrec;
mutable char mySavedFill;
};
执行:
namespace {
int getXAlloc() ;
int ourXAlloc = getXAlloc() + 1 ;
int
getXAlloc()
{
if ( ourXAlloc == 0 ) {
ourXAlloc = std::ios::xalloc() + 1 ;
assert( ourXAlloc != 0 ) ;
}
return ourXAlloc - 1 ;
}
}
StateSavingManip::~StateSavingManip()
{
if ( myStream != nullptr ) {
myStream->flags( mySavedFlags ) ;
myStream->precision( mySavedPrec ) ;
myStream->fill( mySavedFill ) ;
myStream->pword( getXAlloc() ) = NULL ;
}
}
void
StateSavingManip::operator()(
std::ios& stream ) const
{
void*& backptr = stream.pword( getXAlloc() ) ;
if ( backptr == nullptr ) {
backptr = const_cast< StateSavingManip* >( this ) ;
myStream = &stream ;
mySavedFlags = stream.flags() ;
mySavedPrec = stream.precision() ;
mySavedFill = stream.fill() ;
}
setState( stream ) ;
}
注意使用pword
字段来确保只有第一个临时操纵器恢复格式; 析构函数将以相反的构造顺序调用,但如果表达式中有多个这样的操纵符,则通常不会指定构造顺序。
最后:使用这种技术并非一切皆有可能:如果你想系统地在温度上附加度数符号,就没有办法这样做。 在这种情况下,您需要定义一个类Temperature,并为其重载<<
运算符; 这允许一切可以想象的(远远超过你用printf
样式格式化实现的)。
C ++流操纵器( iomanip )专门设计用于支持所有标准c格式说明符操作,只是具有完全不同的接口。 例如, setfill
和setw
为%02d
的宽度和填充部分。
当然如果你真的需要格式化字符串(例如因为它让你更容易),那么你应该看看boost::format
,如果你有C ++ 11那么你可以轻松地在它周围编写小的可变参数模板包装器,使格式调用看起来更像printf。
无论你做什么,请尽量不要使用printf。 对于用户定义类型的输出操作,它不是类型安全的,也不可扩展。
如果你需要它们,有流操纵器。
但我想你想知道这件事:
cout
比printf()
更聪明。 说你有:
int x = 34;
cout<<x;
现在编译器会调用:
ostream& operator<<(ostream& stream, int arg);
为了你。 此函数将在控制台中打印输出(因为在您的情况stream
是cout
)。 对于所有可用的基本数据类型,标准库为此<<
运算符提供重载。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.