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

Har*_*rry 4 c++ format-specifiers

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

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

那么有什么方法可以将这些用于std :: cout吗?

我在课程中得到了一些负面反馈(c ++程序员的c ++),使用printf而不是cout因为我想要一些格式化:(

Dei*_*rei 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;
}
Run Code Online (Sandbox Code Playgroud)

输出: 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;
}
Run Code Online (Sandbox Code Playgroud)

输出:

fixed:
3.14159
2006.00000
0.00000
Run Code Online (Sandbox Code Playgroud)


Jam*_*nze 6

C++ 中通常的解决方案是定义操纵器,说明您尝试格式化的内容,而不是直接在输出点修改物理值。(一个可能的例外是宽度,它std::setw可能直接有用。)因此,例如,当实际输出某些内容时,您不会指定零填充或固定,带有 2 个小数,但类似于:

std::cout << temperature(2) << theTemporature;
Run Code Online (Sandbox Code Playgroud)

哪里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;
    }
};
Run Code Online (Sandbox Code Playgroud)

有关可用格式修改的列表,请参阅 的规范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;
};
Run Code Online (Sandbox Code Playgroud)

执行:

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 ) ;
}
Run Code Online (Sandbox Code Playgroud)

注意pword字段的使用,保证只有第一个临时操作符才能恢复格式;析构函数将以与构造相反的顺序调用,但如果表达式中有多个这样的操纵器,则通常不会指定构造顺序。

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


Joh*_*web 5

C++流不使用像C的printf()类型函数那样的格式说明符; 他们用manipulators.

例如:

#include <iostream>
#include <iomanip>


int main()
{
    std::cout << std::fixed << std::setprecision(6) << 42.0 << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

输出:

42.000000
Run Code Online (Sandbox Code Playgroud)

看它运行!