简体   繁体   English

如何理解 C++ std::setw 的不一致行为?

[英]How to understand C++ std::setw 's inconsistent behaviour?

Given the following code:鉴于以下代码:

/*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

... I get the following output: ...我得到以下输出:

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

... note : I was intentionally "inconsistent" with the code, "because" I'm trying to understand the behavior of the <iomanip> && std::setw() code. ...注意:我故意与代码“不一致”,“因为”我试图了解<iomanip> && std::setw()代码的行为。

If you look at the output from the 1st attempt, you'll notice that the header row "string" output is offset from the data rows "numerical" output... and while it's "mostly" accomplishing the purpose of aligning things in columns, it's both not accurate and not consistent.如果您查看第一次尝试的输出,您会注意到标题行“字符串”输出与数据行“数字”输出偏移......而它“主要”完成了在列中对齐事物的目的,它既不准确也不一致。

In the 2nd attempt, you'll see that I've discovered that if I prepend my row output with:在第二次尝试中,您会发现我发现如果我在行输出前加上:

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

... then I get the row to look correctly ( as seen in the header & 2nd data row ) ... but now you'll notice that the 1st & 3rd data rows are very wrong: ...然后我让行看起来正确(如标题和第二个数据行所示)......但现在您会注意到第一和第三个数据行非常错误:

4545.323         45.5468        
...       
6363.323         63.5468      

... how does "using/executing" ... ......“使用/执行”如何......

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

... affect "future" executions of setw() ? ...影响setw() “未来”执行

For completeness' sake, I've shown in the 3rd Attempt that it's possible to correctly & accurately align columns of data (either left or right) using <iomanip> && std::setw() ... but why the inconsistencies?为完整起见,我在第三次尝试中表明,可以使用<iomanip> && std::setw()正确且准确地对齐数据列(左或右std::setw() ......但为什么会出现不一致?

(@WhozCraig's answer helped me get to where I am, but did not delve deep enough to help me understand either: (a) why it 'pseudo' works || (b) why after you make it work correctly the 'first' time, it then breaks the 'pseudo' functionality.) (@WhozCraig 的回答帮助我找到了我的位置,但也没有深入研究以帮助我理解:(a) 为什么它“伪”有效 || (b) 为什么在你让它“第一次”正常工作之后,然后它会破坏“伪”功能。)

Here's your issue: std::setw() doesn't act as a buffer, it modifies the way the next expression gets evaluated.这是您的问题: std::setw()不充当缓冲区,它修改了下一个表达式的计算方式。

You need to understand the "range" that each of these expressions has.您需要了解每个表达式的“范围”。 Specifically, std::setfill(int) and std::left / std::right change the default behaviour, and seem last until they are overwritten by another setfill() or std::left / std::right .具体来说, std::setfill(int)std::left / std::right改变了默认行为,并且似乎一直持续到它们被另一个setfill()std::left / std::right覆盖。 std::setw(int) on the other hand seems to only affect whatever is passed right after it (which is weird, because I feel like I've also seen it behave like std::setfill and the others before)另一方面, std::setw(int)似乎只影响它之后传递的任何内容(这很奇怪,因为我觉得我也看到它的行为像std::setfill和其他人之前)

So, to sum up, what you want is something more akin to this:所以,总而言之,你想要的是更类似于这个的东西:

    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;

(You'll notice I also changed "\\n" to std::endl which additionally flushes the buffer after each line.) (您会注意到我还将"\\n"更改为std::endl ,这会在每行之后额外刷新缓冲区。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM