在c ++中使用c的各种格式说明符

时间:2013-12-12 09:30:31

标签: c++ format-specifiers

在c中,我们可以使用各种格式说明符,如

  • %nd ,其中n是一个数字,打印的数字总共至少覆盖了n个空间
  • %0nd 与上述相同,除了预填充0 “%05d”,3 => 00003
  • %。nf 设置小数后n的精度
  • 等....

那么有没有办法将这些用于 std :: cout

我在课程中得到了一些负面反馈(c ++程序员的c ++),使用 printf 代替 cout ,因为我想要一些格式:(< / p>

5 个答案:

答案 0 :(得分:6)

对于%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::setprecisionstd::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

答案 1 :(得分:5)

C++ stream不要使用C&#39 {s} printf()类型函数之类的格式说明符;他们使用manipulators

例如:

#include <iostream>
#include <iomanip>


int main()
{
    std::cout << std::fixed << std::setprecision(6) << 42.0 << std::endl;
}

输出:

42.000000

See it run!

答案 2 :(得分:4)

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字段来确保只有第一个字段 临时操纵器恢复格式;析构者会 按照与建筑相反的顺序进行调用,但顺序为 如果您有更多,通常不会指定施工 而不是表达式中的一个这样的操纵者。

最后:使用这种技术并非一切皆有可能:如果你 想系统地在温度上附加度数符号, 没有办法这样做。在这种情况下,您需要定义 一个类温度,并为其<<运算符重载;这个 允许一切可以想象的(远远超过你所能做到的) 以printf样式格式实现。

答案 3 :(得分:2)

C ++流操作符(iomanip)专门用于支持所有标准c格式说明符操作,只是具有完全不同的接口。例如。 setfillsetw代表%02d的宽度和填充部分。

当然如果你真的需要格式化字符串(例如因为它让你更容易),那么你应该看看boost::format,如果你有C ++ 11,那么你可以轻松地编写小的可变参数围绕它的模板包装,使格式调用看起来更像printf。

无论你做什么,请尽量不要使用printf。对于用户定义类型的输出操作,它不是类型安全的,也不可扩展。

答案 4 :(得分:1)

如果你需要它们,还有流动操纵器。
但我想你想知道这件事:
coutprintf()更聪明。 说你有:

int x = 34;
cout<<x;

现在编译器将调用:

ostream& operator<<(ostream& stream, int arg);

给你。此函数将在控制台中打印输出(因为在您的情况下streamcout)。对于所有可用的基本数据类型,标准库为此<<运算符提供重载。