Problems with cout in C++

Viewed 212

To start, I want to show you my code below.

#include<iostream>

int main()
{
    float num = 3;
    std::ios_base::fmtflags initial;
    initial = std::cout.setf(std::ios_base::fixed);
    std::cout.setf(initial);
    std::cout<<num;
}

The output is 3.000000. With only first and last lines output is 3. My book says that "The setf() method returns a copy of all the formatting settings in effect before the call was made. std::ios_base::fmtflags is a fancy name for the type needed to store this information. So the assignment to initial stores the settings that were in place before the setf function was called. The initial variable can then be used as an argument to setf() to reset all the formatting settings to this original value." But as you can see, it doesn't work. What's the issue?

4 Answers

From std::ios_base::setf:

fmtflags setf( fmtflags flags ); (1)
fmtflags setf( fmtflags flags, fmtflags mask ); (2)
Sets the formatting flags to specified settings.

  1. Sets the formatting flags identified by flags. Effectively the following operation is performed fl = fl | flags where fl defines the state of internal formatting flags.
  2. Clears the formatting flags under mask, and sets the cleared flags to those specified by flags. Effectively the following operation is performed fl = (fl & ~mask) | (flags & mask) where fl defines the state of internal formatting flags.

(Emphasize is mine.)

So, std::ios::setf() is a good choice to set individual flags but it's a bad choice to set all flags at once.

For this, std::ios_base::flags is the right tool:

fmtflags flags() const; (1)
fmtflags flags( fmtflags flags ); (2)
Manages format flags.

  1. returns current formatting setting

  2. replaces current settings with given ones.

Sample:

#include<iostream>

int main()
{
    float num = 3;
    std::cout<<num<<'\n';
    std::ios_base::fmtflags initial;
    initial = std::cout.setf(std::ios_base::fixed);
    std::cout.flags(initial); // <-- the fix
    std::cout<<num<<'\n';
}

Output:

3
3

Live Demo on coliru

Some of the format flags are mutually exclusive.

For example, std::ios_base::left can not be used together std::ios_base::right. std::ios_base::fixed is an exclusive flags also. It can not be used with std::ios_base::scientific. To exclusively set a format flag, std::ios_base::setf() takes additional bit group flag as its second parameter. You can then set a format flag correctly. std::ios_base::fixed is a group of std::ios_base::floatfield and you should set it as its second parameter when calling setf().

#include <iostream>

int main(void)
{
    float num = 3;

    std::ios_base::fmtflags initial;
    initial = std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
    std::cout.setf(initial, std::ios_base::floatfield);

    std::cout << num;  // 3 printed on VS2019

    return 0;
}

You can also simply use io manipulators. (It's also more readable code):

#include<iostream>

int main()
{
    float num = 3;
    
    std::cout<< std::fixed;
    
    std::cout << num<<'\n';
    std::cout<<num<<'\n';
    
    std::cout << std::scientific;

    std::cout << num<<'\n';
    std::cout<<num<<'\n';
    
    std::cout << std::defaultfloat;

    std::cout << num<<'\n';
    std::cout<<num<<'\n';
    
    

}

Live on coliru

Output:

3.000000
3.000000
3.000000e+00
3.000000e+00
3
3

setf is used to set a specific format flag. So it does not reset the set fixed flag when you call std::cout.setf(initial); You probably want to use the flags function instead:

#include <iostream>

int main()
{
    const double num = 3.0;
    std::cout << num << '\n';
    const auto initial_flags = std::cout.flags(std::ios_base::fixed);
    std::cout << num << '\n';
    std::cout.flags(initial_flags);
    std::cout << num << '\n';
}

Output:

3
3.000000
3
Related