【问题标题】:Why does cout.precision() affect the whole stream?为什么 cout.precision() 会影响整个流?
【发布时间】:2016-02-09 06:40:51
【问题描述】:

我觉得我在问一个非常基本的问题,但我无法在这里或在 Google 中找到答案。我记得我们在学校被教过这个,但是多年来它已经消失了。

为什么在输出列表中间调用cout.precision() (std::ios_base::precision()) 会影响整个流?我知道应该使用std::setprecision() 来动态更改精度的规则,并且cout.precision() 会用它返回的值破坏输出。但这是什么机制呢?是缓冲的原因吗?手册说这些“做同样的事情”,但凭经验我可以看出这并不完全正确。

MCVE:

const double test = 1.2345;
cout.setf(ios::fixed);
cout.setf(ios::showpoint);
cout.precision(2);
cout << test << endl << cout.precision(3) <<  test << endl;

// Output:
// 1.234
// 21.234

// after the same init
cout.precision(2);
cout << test << endl << setprecision(3) <<  test << endl;

// Output
// 1.23
// 1.234

这是“特定于实施/标准未定义”吗? 请随意将其标记为重复,因为我无法在 SO 上找到它。

【问题讨论】:

    标签: c++ iostream c++-standard-library


    【解决方案1】:

    函数参数求值的顺序未指定。当您调用std::cout.precision(n) 时,std::cout' 的精度设置在评估此调用的点。在你的表情中

    cout << test << endl << cout.precision(3) <<  test << endl;
    

    cout.precision(3) 显然是编译器完全允许做的第一件事。请记住,编译器认为上述语句等同于

    std::cout.operator<<(test)
              .operator<<(std::endl)
              .operator<<(std::cout.preision(3))
              .operator<<(test)
              .operator<< (std::endl);
    

    实际上,您的编译器函数参数似乎是从右到左计算的。然后才执行不同的移位运算符。结果,精度在输出完成之前就发生了变化。

    使用像std::setprecision(n) 这样的操作符可以避免依赖于顺序子表达式的求值:从std::setprecision(n) 创建的临时值是随时创建的。然后在调用适当的移位运算符时应用效果。由于必须以适当的顺序调用移位运算符,因此操纵器的使用发生在已知位置。

    【讨论】:

    • 太好了,太详细了!但是代码行之间是否存在拼写错误?看起来一个operator&lt;&lt;() 呼叫丢失了。
    • 另外,我是否正确理解setprecision()的效果正是因为它返回了一个临时对象,其创建点和调用点在时间上是分开的?
    • @iksemyonov:我认为所有运营商的电话都在那里,但实际上有一个是错误的(它实际上也是一个成员)。是的,std::setprecision(n) 使用operator&lt;&lt;() 调用创建了一个临时“插入”到流中。插入此临时值时,不会写入任何字符,但会更改精度。创建和插入时间不同。
    【解决方案2】:

    没有定义在您的第一个示例中评估 cout.precision(3) 的确切时间,因为它的值用作函数调用的参数。 OTOH 在第二个示例中,setprecision(3) 插入流的时间非常明确 - 即在插入 endl 之后和 test 之前(第二次)。因此第一个版本不会产生可靠的结果(在不同的实现中你得到的结果可能不同),但第二个版本会。

    有关更详细的说明,请参阅this question。 (那里的问题没有使用运算符,但原理是一样的——在另一个函数的返回值上调用一个成员函数。)

    【讨论】:

    • 以前对此一无所知!阅读。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-19
    • 1970-01-01
    • 2016-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-06
    相关资源
    最近更新 更多