Использование различных спецификаторов формата c в C++

Как и в C мы можем использовать различные спецификаторы формата, такие как

  • % nd, где n - это число, чтобы напечатать число с общим количеством не менее n пробелов
  • % 0 и то же, что и выше, за исключением предварительного дополнения 0 "% 05d", 3 => 00003
  • %.nf, чтобы установить точность n после десятичной
  • так далее....

Так есть ли способ использовать их с std:: cout?

Я получил некоторые отрицательные отзывы в недавнем курсе (C++ для программистов на c) в Coursera, за использование printf вместо cout, потому что я хотел немного отформатировать:(

5 ответов

Решение

За %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 а также 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 может быть полезным непосредственно.) Таким образом, например, при фактическом выводе чего-либо вы не будете указывать заполнение нулями или фиксированное значение с двумя десятичными знаками, а что-то вроде:

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,

Конечно, если вам действительно нужны строки формата (например, потому что это облегчает i18n), то вам стоит взглянуть на boost::format, и если у вас есть C++11, то вы можете легко написать вокруг него небольшую переменную оболочку шаблона, чтобы вызов формата был больше похож на printf.

Что бы вы ни делали, пожалуйста, старайтесь не использовать printf. Он не безопасен для типов и не расширяется для операций вывода для пользовательских типов.

Есть потоковые манипуляторы, если они вам нужны.
Но я думаю, что вы хотите знать эту вещь:
cout умнее чем printf(), Скажем, у вас есть:

int x = 34;
cout<<x;

Теперь компилятор вызовет:

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

для тебя. И эта функция будет печатать вывод в консоли (так как в вашем случае stream является cout). Стандартная библиотека предоставляет перегрузки для этого << оператор для всех основных типов данных.

Другие вопросы по тегам