Search code examples
c++stringstring-formatting

How to get a formatted std::string in c++ without length liminations


What is the best way (short, using standard libraries and easy to understand) to do this in c++:

std::string s = magic_command("%4.2f", 123.456f)
  • without length limitations (char s[1000] = ...)
  • where "%4.2f" is any c format string (which would be given to printf for example)

I am aware of the snprintf malloc combo suggested for pure c in

writing formatted data of unknown length to a string (C programming)

but is there a better, less verbose, way to do this with c++?

I am also aware of the std::ostringstream method suggested in

Convert float to std::string in C++

but I want to pass a c format string such as "%4.2f", and I could not find a way to do this with ostringstream.


Solution

  • New answer 10 years later: C++20 std::format

    Finally, this will be the superior choice once you can use it:

    #include <format>
    #include <string>
    
    int main() {
        std::cout << std::format("{:4.3}\n{:4.3}\n", 3.1, 3.1415);
    }
    

    Expected output:

     3.1
    3.14
    

    This will therefore completely overcome the madness of modifying std::cout state.

    The existing fmt library implements it for before it gets official support: https://github.com/fmtlib/fmt Install on Ubuntu 22.04:

    sudo apt install libfmt-dev
    

    Modify source to replace:

    • <format> with <fmt/core.h>
    • std::format to fmt::format

    main.cpp

    #include <iostream>
    
    #include <fmt/core.h>
    
    int main() {
        std::cout << fmt::format("{:4.3}\n{:4.3}\n", 3.1, 3.1415);
    }
    

    and compile and run with:

    g++ -std=c++11 -o main.out main.cpp -lfmt
    ./main.out
    

    Output:

     3.1
    3.14
    

    Old answer

    All answers given are good since there seems to be no really standard way of doing what I want, I'll vote you all up, and accept my own sum up course of action:

    • if the string is short enough to estimate its size by hand, do it, multiply your estimative by 4, and allocate it statically.
    • if you can get away with stringstream + setprecision, do it since it is standard
    • if not, and you are willing to write and include a short helper function based on snprintf/check overflow/dynamic allocation, do it and put it into your project "utils" file
    • finnally consider which dependency is less restrictive for your project (maybe you are already using one of them):
      • if boost is less restrictive, use Boost.Format
      • if GNU/BSD extensions are less restrictive, use asprintf