std :: ostream的浮点格式

时间:2012-08-16 14:28:21

标签: c++ floating-point cout ostream

如何使用std :: cout执行以下操作?

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

我准备放弃并使用sprintf_s。

更一般地说,我在哪里可以找到std :: ostream格式的引用,它在一个地方列出所有内容,而不是在长篇教程中全部展开?

编辑2017年12月21日 - 请参阅下面的答案。它使用了我在2012年提出这个问题时无法使用的功能。

8 个答案:

答案 0 :(得分:64)

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

您需要添加

#include <iomanip>

您需要stream manipulators

你可以用你想要的任何字符“填充”空白的地方。像这样:

std::cout << std::fixed << std::setw( 11 ) << std::setprecision( 6 ) 
          << std::setfill( '0' ) << my_double;

答案 1 :(得分:14)

std::cout << boost::format("%11.6f") % my_double;

您必须#include <boost\format.hpp>

答案 2 :(得分: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;
}

答案 3 :(得分:6)

在C ++ 20中,您将能够做到

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

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

同时,您可以使用提供format_to_n实现的the {fmt} library

免责声明:我是{fmt}和C ++ 20 std::format的作者。

答案 4 :(得分:5)

一般情况下,您希望避免在{。{1}}和11中指定内容 输出点。这是物理标记,你想要逻辑标记; 例如6pressure。这样,您可以在一个地方定义 如何格式化压力或体积,以及格式是否发生变化, 您不必搜索程序以找到要更改的位置 格式(并意外地改变其他东西的格式)。在 C ++,你可以通过定义一个设置各种设置的操纵器来实现 格式化选项,并最好在完整的结束时恢复它们 表达。所以你最终写的东西如下:

volume

虽然我绝对不会在生产代码中使用它,但我发现了 以下std::cout << pressure << my_double; 格式化程序对快速作业非常有用:

FFmt

这允许编写如下内容:

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

记录:

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

StateSavingManip.cc:

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

答案 5 :(得分:1)

这是我,OP,Jive Dadson--五年过去了。 C ++ 17正在成为现实。

具有完美转发的可变参数模板参数的出现使生活变得如此简单。 ostream的链式疯狂&lt;&lt;和boost :: format%可以免除。下面的函数oprintf填写账单。工作正在进行中。随意加入错误处理等等......

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

答案 6 :(得分:1)

对于喜欢使用std :: ostream的实际printf样式格式规范的未来访问者,这是另一个变体,基于Martin York在另一个SO问题中的优秀帖子: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);
    }
};

用法示例:

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

甚至:

int val = 42;
cout << val << " in hex is " << FMT(" 0x%x") << val << "\n";

答案 7 :(得分:0)

已经有了一些很好的答案;对那些人表示敬意!

这是基于其中一些。我为POD类型添加了类型断言,因为它们是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

示例用法如下。

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

Give it a try on Coliru