54

How do I do the following with std::cout?

double my_double = 42.0;
char str[12];
printf_s("%11.6lf", my_double); // Prints " 42.000000"

I am just about ready to give up and use sprintf_s.

More generally, where can I find a reference on std::ostream formatting that lists everything in one place, rather than spreading it all out in a long tutorial?

EDIT Dec 21, 2017 - See my answer below. It uses features that were not available when I asked this question in 2012.

Jive Dadson
  • 16,680
  • 9
  • 52
  • 65
  • The format specifier for `printf` should be "%11.6f". There's no "lf" format specifier, and "Lf" would be for `long double`. – Pete Becker Aug 16 '12 at 14:34
  • 4
    @pete - Well you learn something every day. I have been using %lf for 28 years. – Jive Dadson Aug 16 '12 at 14:51
  • 2
    @Pete @Jive: There is nothing wrong with using `%lf`; the `l` is simply ignored according to the standard. See http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html, or your favorite C spec. – Nemo Aug 16 '12 at 14:54
  • @JiveDadson - don't want to go to far off on this tangent, but is that with the same compiler, or spread across various ones? – Pete Becker Aug 16 '12 at 14:55
  • 1
    @pete Everything from the PCC ca. 1984 to VC++ 2010 about five minutes ago. – Jive Dadson Aug 16 '12 at 14:57
  • 1
    @PeteBecker: There is a "lf" format specifier. From the C99 standard, "[the "l" modifier] has no effect on a following a, A, e, E, f, F, g, or G conversion specifier." In other words, "lf" means the same as "f". – David Hammen Aug 16 '12 at 15:00
  • As @Nemo pointed out, the 'l' is ignored here, so formally it's valid. – Pete Becker Aug 16 '12 at 15:00
  • 3
    The reason %lf exists is so one can use the same format string for scanf and printf. You have to tell scanf whether the arg is a float (%f) or a double (%lf). Get it wrong and your program goes kablooey. – Jive Dadson Aug 16 '12 at 17:18
  • wow, all that work to merely print a float, and people complained that printf was complicated. – Rainb Nov 26 '19 at 22:39

8 Answers8

86
std::cout << std::fixed << std::setw(11) << std::setprecision(6) << my_double;

You need to add

#include <iomanip>

You need stream manipulators

You may "fill" the empty places with whatever char you want. Like this:

std::cout << std::fixed << std::setw(11) << std::setprecision(6) 
          << std::setfill('0') << my_double;
Kiril Kirov
  • 37,467
  • 22
  • 115
  • 187
  • 1
    Which ones? Where do I put the 11 and where do I put the 6? – Jive Dadson Aug 16 '12 at 14:47
  • To match the original format specifier this also needs `std::setw(11)`. And as a side note, for the specific case of a precision of 6, you don't need to say it, neither in C nor C++, because it's the default. – Pete Becker Aug 16 '12 at 14:51
  • @JiveDadson - sorry, I missed the `11`. Edited. – Kiril Kirov Aug 16 '12 at 15:02
  • @JiveDadson - it is, by default. I just mentioned, that could be customized. – Kiril Kirov Aug 17 '12 at 06:26
  • 2
    +1 for including the include statement, too many people don't – marcp Oct 28 '14 at 16:06
  • 4
    This is a great solution to the OP, but be aware that these are stream manipulators; i.e they modify the stream and you will have to [revert it](https://stackoverflow.com/questions/2273330/restore-the-state-of-stdcout-after-manipulating-it) or change it to something else each time you need a different format. It is more of a problem if the stream being manipulated is a "long-living one", like `std::cout`, `std::cerr`, logging stream, etc. In those cases it will be less cumbersome to use one of the solutions suggested in other answers here. – ϹοδεMεδιϲ Oct 02 '20 at 09:46
15
std::cout << boost::format("%11.6f") % my_double;

You have to #include <boost\format.hpp>

Andriy
  • 8,486
  • 3
  • 27
  • 51
  • I remember I used to use that long ago on a project far, far away. Thanks for reminding me. I wish I could use boost for what I am working on, but alas... – Jive Dadson Aug 16 '12 at 14:53
13

In C++20 you can to do

double my_double = 42.0;
char str[12];
std::format_to_n(str, sizeof(str), "{:11.6}", my_double); 

or

std::string s = std::format("{:11.6}", my_double); 

In pre-C++20 you can use the {fmt} library that provides an implementation of format_to_n.

Disclaimer: I'm the author of {fmt} and C++20 std::format.

vitaut
  • 49,672
  • 25
  • 199
  • 336
8

In general, you want to avoid specifying things like 11 and 6 at the point of output. That's physical markup, and you want logical markup; e.g. pressure, or volume. That way, you define in a single place how pressure or volume are formatted, and if that formatting changes, you don't have to search through out the program to find where to change the format (and accidentally change the format of something else). In C++, you do this by defining a manipulator, which sets the various formatting options, and preferrably restores them at the end of the full expression. So you end up writing things like:

std::cout << pressure << my_double;

Although I definitly wouldn't use it in production code, I've found the following FFmt formatter useful for quicky jobs:

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 )
}

This allows writing things like:

std::cout << FFmt( 11, 6 ) << my_double;

And for the record:

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;
}

StateSavingManip.cc:

namespace {

//      We maintain the value returned by ios::xalloc() + 1, and not
//      the value itself.  The actual value may be zero, and we need
//      to be able to distinguish it from the 0 resulting from 0
//      initialization.  The function getXAlloc() returns this value
//      -1, so we add one in the initialization.
int                 getXAlloc();
int                 ourXAlloc = getXAlloc() + 1;

int
getXAlloc()
{
    if ( ourXAlloc == 0 ) {
        ourXAlloc = std::ios::xalloc() + 1;
        assert( ourXAlloc != 0 );
    }
    return ourXAlloc - 1;
}
}

StateSavingManip::StateSavingManip()
    :   myStream( NULL )
{
}

StateSavingManip::StateSavingManip(
    StateSavingManip const&
                        other )
{
    assert( other.myStream == NULL );
}

StateSavingManip::~StateSavingManip()
{
    if ( myStream != NULL ) {
        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 == NULL ) {
        backptr      = const_cast< StateSavingManip* >( this );
        myStream     = &stream;
        mySavedFlags = stream.flags();
        mySavedPrec  = stream.precision();
        mySavedFill  = stream.fill();
    }
    setState( stream );
}
James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • That's some mighty nice stuff, and I thank you. To everybody: I have to leave for a while. Thanks for all the help. It appears there is no perfect answer, but I have learned a lot, and even remembered some things I had forgotten. When I get back I will struggle with where to put the green check mark. – Jive Dadson Aug 16 '12 at 16:15
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;
}
Pete Becker
  • 74,985
  • 8
  • 76
  • 165
  • Not quite what I need. Maybe I asked the question wrong. I want it always to print 11 characters, no more, no less. When I give that 0.1, it prints "0.100000" which is only 8 characters. – Jive Dadson Aug 16 '12 at 15:08
  • 1
    @JiveDadson - works fine for me. When I give that 0.1 it prints " 0.100000", which is 11 characters. (Note that there are three leading spaces in the actual output; they seem to have gotten swallowed in word wrapping. – Pete Becker Aug 16 '12 at 15:15
  • Note that setw(11) does not set the output to be exactly 11 characters. It sets the field width to be at least 11 characters. E.g., printing 42e5 with this format produces 14 characters. – Eric Postpischil Aug 16 '12 at 15:19
  • This is driving me bonkers. It's so easy with printf, and so short. I might just have to rip off boost/format, as Andrey suggested. I have despised iostreams since the first day they were introduced. I have fought this battle a lot of times, but I always forget the devilish details. – Jive Dadson Aug 16 '12 at 15:23
  • @JiveDadson - yes, it's verbose. If you're going to do the same thing frequently (i.e. more than once), write a manipulator that does it. Still not as simple as `printf`, of course. – Pete Becker Aug 16 '12 at 15:24
  • When I added std::setfill(' ') to the mix, it worked on the first number, then reverted. – Jive Dadson Aug 16 '12 at 15:28
  • "11 characters, no more, no less"? The format specifier in the original example doesn't do that. More important, what do you want it to do when the displayed value won't fit in 11 characters? (42e5, as @EricPostpischil mentioned) – Pete Becker Aug 16 '12 at 15:29
  • @JiveDadson: And, please, use http://en.cppreference.com/w/cpp/io/manip/setprecision as C++ reference. – SChepurin Aug 16 '12 at 15:35
  • The values will never overflow 11 places, so it's moot, but if by accident one would not fit, I would want the formatter to behave the way %11.6f does. @SChepurin, thanks for the link. – Jive Dadson Aug 16 '12 at 15:40
  • Wait a minute. I think it's the setw(11) that is only working for the first number then being forgotten. – Jive Dadson Aug 16 '12 at 15:45
  • setw isn't sticky. It gets cleared after the next insertion. So if you're inserting more than one value with the same statement, you have to repeat it. – Pete Becker Aug 16 '12 at 15:46
  • I can't repeat it without changing the interface. I tried cout.width(11), but that was not sticky either. I think I give up now. Will either sneak boost/format into the thing or roll my own equivalent. Did I mention that I detest iostreams? – Jive Dadson Aug 16 '12 at 15:55
  • `std::cout << std::setw(11) << foo << std::setw(11) << bar;` – Pete Becker Aug 16 '12 at 15:58
  • @JiveDadson - "if by accident one would not fit, I would want the formatter to behave the way %11.6f does" -- the code I gave you does that. Both forms set the **minimum** field width. If the value is too large for that width they will produce more characters as needed. – Pete Becker Aug 16 '12 at 16:31
2

For future visitors who prefer actual printf-style format specs with std::ostream, here is yet another variation, based on Martin York's excellent post in another SO question: 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);
    }
};

usage example:

double my_double = 42.0;
cout << FMT("%11.6f") << my_double << "more stuff\n";

or even:

int val = 42;
cout << val << " in hex is " << FMT(" 0x%x") << val << "\n";
djulien
  • 141
  • 1
  • 2
1

it's me, the OP, Jive Dadson - five years on. C++17 is becoming a reality.

The advent of variadic template parameters with perfect forwarding has made life so much simpler. The chained madness of ostream<< and boost::format% can be dispensed with. The function oprintf below fills the bill. Work in progress. Feel free to chime in on error-handling, etc...

#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;
}
Jive Dadson
  • 16,680
  • 9
  • 52
  • 65
  • 1
    Using a string_view as an input for C-style functions is dangerous as it is not necessarily null-terminated. – Dominik Aug 16 '19 at 18:53
0

Some great answers already; kudos to those!

This is based on some of them. I have added type assertions for POD types, since they are the only safe types usable with 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

Example usage it as below.

std::cout << fmt::printf("%11.6f", my_double);

Give it a try on Coliru.

ϹοδεMεδιϲ
  • 2,790
  • 3
  • 33
  • 54