【问题标题】:How to understand C++ std::setw 's inconsistent behaviour?如何理解 C++ std::setw 的不一致行为?
【发布时间】:2018-09-24 06:48:34
【问题描述】:

给定以下代码:

/*Formatting Output 
**Goal: practice using cout to format output to console
**Print the variables in three columns:
**Ints, Floats, Doubles
*/

#include <iostream>
#include <iomanip>

using namespace std;

int main()
{
    int a = 45;
    float b = 45.323;
    double c = 45.5468;
    int aa = a + 9;
    float bb = b + 9;
    double cc = c + 9;
    int aaa = aa + 9;
    float bbb = bb + 9;
    double ccc = cc + 9;

    // 1st attempt :>

    cout << "\n\n\n" << "// 1st attempt :>" << "\n";
    cout << "12345678901234567890123456789012345678901234567890" << "\n";
    cout << "Ints" << setw(15) << "Floats" << setw(15) << "Doubles" << "\n";
    cout << a << setw(15) << b << setw(15) << c << "\n";
    cout << aa << setw(15) << bb << setw(15) << cc << "\n";
    cout << aaa << setw(15) << bbb << setw(15) << ccc << "\n";


    // 2nd attempt :>

    cout << "\n\n\n" << "// 2nd attempt :>" << "\n";
    cout << "12345678901234567890123456789012345678901234567890" << "\n";
    cout << std::left << std::setfill(' ') << std::setw(15)  << "Ints" << setw(15) << "Floats" << setw(15) << "Doubles" << "\n";
    cout << a << setw(15) << b << setw(15) << c << "\n";
    cout << std::left << std::setfill(' ') << setw(15) << aa << setw(15) << bb << setw(15) << cc << "\n";
    cout << aaa << setw(15) << bbb << setw(15) << ccc << "\n";

    // 3rd attempt :>

    cout << "\n\n\n" << "// 3rd attempt :>" << "\n";
    cout << "12345678901234567890123456789012345678901234567890" << "\n";
    cout << std::left << std::setfill(' ') << std::setw(15) << "Ints" << setw(15) << "Floats" << setw(15) << "Doubles" << "\n";
    cout << std::left << std::setfill(' ') << std::setw(15) << a << setw(15) << b << setw(15) << c << "\n";
    cout << std::left << std::setfill(' ') << std::setw(15) << aa << setw(15) << bb << setw(15) << cc << "\n";
    cout << std::left << std::setfill(' ') << std::setw(15) << aaa << setw(15) << bbb << setw(15) << ccc << "\n";
    cout << "12345678901234567890123456789012345678901234567890" << "\n";
    cout << std::right << std::setfill(' ') << std::setw(15) << "Ints" << setw(15) << "Floats" << setw(15) << "Doubles" << "\n";
    cout << std::right << std::setfill(' ') << std::setw(15) << a << setw(15) << b << setw(15) << c << "\n";
    cout << std::right << std::setfill(' ') << std::setw(15) << aa << setw(15) << bb << setw(15) << cc << "\n";
    cout << std::right << std::setfill(' ') << std::setw(15) << aaa << setw(15) << bbb << setw(15) << ccc << "\n";

    return 0;
}
// https://repl.it/@Tredekka/Cpp-Understanding-stdsetw

...我得到以下输出:

gcc version 4.6.3

// 1st attempt :>
12345678901234567890123456789012345678901234567890
Ints         Floats        Doubles
45         45.323        45.5468
54         54.323        54.5468
63         63.323        63.5468



// 2nd attempt :>
12345678901234567890123456789012345678901234567890
Ints           Floats         Doubles        
4545.323         45.5468        
54             54.323         54.5468        
6363.323         63.5468        



// 3rd attempt :>
12345678901234567890123456789012345678901234567890
Ints           Floats         Doubles        
45             45.323         45.5468        
54             54.323         54.5468        
63             63.323         63.5468        
12345678901234567890123456789012345678901234567890
           Ints         Floats        Doubles
             45         45.323        45.5468
             54         54.323        54.5468
             63         63.323        63.5468

... 注意:我故意与代码“不一致”,“因为”我试图理解 &lt;iomanip&gt; && @ 的行为987654325@代码。

如果您查看第一次尝试的输出,您会注意到标题行“字符串”输出与数据行“数字”输出偏移......虽然它“主要”实现了对齐的目的列中的东西,既不准确也不一致。

在第二次尝试中,您会发现我发现如果我在行输出前添加:

<< std::left << std::setfill(' ') << setw(15)

...然后我让该行看起来正确(如在标题和第二个数据行中看到的)...但是现在您会注意到第一个和第三个数据行非常错误:

4545.323         45.5468        
...       
6363.323         63.5468      

...“使用/执行”如何...

<< std::left << std::setfill(' ') << setw(15)

...影响setw()的“未来”执行?

为了完整起见,我在第三次尝试中展示了使用&lt;iomanip&gt; && std::setw() 可以正确和准确地对齐数据列(左或右)...但是为什么会出现不一致?

(@WhozCraig 的 answer 帮助我到达了现在的位置,但也没有深入研究以帮助我理解:(a) 为什么它“伪”有效 || (b) 为什么在你让它正常工作之后“第一次”,然后打破“伪”功能。)

【问题讨论】:

  • 完全一致。在第一次尝试中,标题行以 4 个字符开始,然后是 15 个字符(主要是空格),然后是 15 个字符(同样主要是空格)。下一行是 2 个字符,然后是 15 个字符,然后是 15 个字符。要对齐,您还必须设置第一列的宽度。
  • 不一致是什么意思? Ints 是 4 个字符,而 45 是 2,这就是为什么 1st 没有对齐。
  • @PeteBecker ~ 好吧,我现在明白你为什么说第一次尝试是一致的......“默认情况下”setw() 必须有效地leftPad/right-justify 列默认(不是它如何由我正在关注的教程解释)...话虽如此,它仍然没有解决第二次尝试的第 1 和第 3 数据行的奇怪问题。?。
  • @George2.0希望你必须设置输出宽度first,第一列也是如此
  • @KillzoneKid wrt 第一次尝试,根据我对@PeteBecker 的回复,我理解;但是,即使我改变了 2ndAttempt 这样做,它仍然不能修复第 1 和第 3 数据行。

标签: c++ std iomanip setw


【解决方案1】:

这是您的问题:std::setw() 不充当缓冲区,它会修改下一个表达式的求值方式。

您需要了解每个表达式的“范围”。具体来说,std::setfill(int)std::left/std::right 会更改默认行为,并且在它们被另一个 setfill()std::left/std::right 覆盖之前似乎是最后一个。另一方面,std::setw(int) 似乎只影响紧随其后传递的任何内容(这很奇怪,因为我觉得我也看到它的行为类似于 std::setfill 和之前的其他内容)

所以,总而言之,你想要的是更类似于这样的东西:

    int a = 45;
    float b = 45.323;
    double c = 45.5468;
    int aa = a + 9;
    float bb = b + 9;
    double cc = c + 9;
    int aaa = aa + 9;
    float bbb = bb + 9;
    double ccc = cc + 9;


    std::cout << std::endl << std::endl << std::endl;

    std::cout << std::left << std::setfill('~');

    // 1st attempt :>
    std::cout << "// 1st attempt :>" << std::endl;
    std::cout << "12345678901234567890123456789012345678901234567890" << std::endl;
    std::cout << std::setw(10) << "Ints" << std::setw(10) << "Floats" << std::setw(10) << "Doubles" << std::endl;
    std::cout << std::setw(10) << a   << std::setw(10) << b   << std::setw(10) << c   << std::endl;
    std::cout << std::setw(10) << aa  << std::setw(10) << bb  << std::setw(10) << cc  << std::endl;
    std::cout << std::setw(10) << aaa << std::setw(10) << bbb << std::setw(10) << ccc << std::endl;


    std::cout << std::endl << std::endl << std::endl << std::setfill('*');


    // 2nd attempt :>
    std::cout << "// 2nd attempt :>" << std::endl;
    std::cout << "12345678901234567890123456789012345678901234567890" << std::endl;
    std::cout << std::setw(10) << "Ints" << std::setw(10) << "Floats" << std::setw(10) << "Doubles" << std::endl;
    std::cout << std::setw(10) << a   << std::setw(10) << b   << std::setw(10) << c   << std::endl;
    std::cout << std::setw(10) << aa  << std::setw(10) << bb  << std::setw(10) << cc  << std::endl;
    std::cout << std::setw(10) << aaa << std::setw(10) << bbb << std::setw(10) << ccc << std::endl;


    std::cout << std::endl << std::endl << std::endl;


    // 3rd attempt :>
    std::cout << "// 3rd attempt :>" << std::endl;
    std::cout << "12345678901234567890123456789012345678901234567890" << std::endl;
    std::cout << std::setw(10) << "Ints" << std::setw(10) << "Floats" << std::setw(10) << "Doubles" << std::endl;
    std::cout << std::setw(10) << a   << std::setw(10) << b   << std::setw(10) << c   << std::endl;
    std::cout << std::setw(10) << aa  << std::setw(10) << bb  << std::setw(10) << cc  << std::endl;
    std::cout << std::setw(10) << aaa << std::setw(10) << bbb << std::setw(10) << ccc << std::endl;

    std::cout << "12345678901234567890123456789012345678901234567890" << std::endl;
    std::cout << std::right << std::setfill(' ');
    std::cout << std::setw(10) << "Ints" << std::setw(10) << "Floats" << std::setw(10) << "Doubles" << std::endl;
    std::cout << std::setw(10) << a   << std::setw(10) << b   << std::setw(10) << c   << std::endl;
    std::cout << std::setw(10) << aa  << std::setw(10) << bb  << std::setw(10) << cc  << std::endl;
    std::cout << std::setw(10) << aaa << std::setw(10) << bbb << std::setw(10) << ccc << std::endl;

    std::cout << std::endl << std::endl << std::endl;

(您会注意到我还将"\n" 更改为std::endl,这还会在每行之后刷新缓冲区。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-20
    • 2021-12-02
    • 2021-04-23
    相关资源
    最近更新 更多