Setting Width in C++ Output Stream

Setting width in C++ output stream

You can create an object that overloads operator<< and contains an iostream object that will automatically call setw internally. For instance:

class formatted_output
{
private:
int width;
ostream& stream_obj;

public:
formatted_output(ostream& obj, int w): width(w), stream_obj(obj) {}

template<typename T>
formatted_output& operator<<(const T& output)
{
stream_obj << setw(width) << output;

return *this;
}

formatted_output& operator<<(ostream& (*func)(ostream&))
{
func(stream_obj);
return *this;
}
};

You can now call it like the following:

formatted_output field_output(cout, 10);
field_output << x << y << endl;

Setting width of text mentioned inside printf

If I understand your question correctly, you want to sneak in the tidy output behind the scenes without "intruding" on the existing code.

First, replace printf with a custom name. Then you can write a wrapper around it. If your compiler understands variadic macros, this may just be a macro. Otherwise you can roll your own printf-like function with variadic arguments and vprintf.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#if VAR_ARG_MACRO_AVAILABLE

#define tprintf(fmt, ...) do { \
printf("%.*s", 24 - strlen(fmt), \
" "); \
printf(fmt, __VA_ARGS__); \
} while (0)

#else

#include <stdarg.h>

int tprintf(const char *fmt, ...)
{
va_list va;
int n;

va_start(va, fmt);

n = 24 - strlen(fmt);
if (n < 0) n = 0;
printf("%.*s", n, " ");

n += vprintf(fmt, va);

va_end(va);

return n;
}

#endif

int main()
{
tprintf("a = %d\n", 2);
tprintf("alpha = %d\n", 21);
tprintf("alphabetical = %d\n", 112);

return 0;
}

The macro solution relies on variable names of less than about twenty characters. Otherwise, the absolute value of the field width will be taken, which may mangle your layout.

Using strlen (and not, for example, strchr(fmt, '=')), is an approximation and will not work if you have format specifiers of different lengths, e.g. %zu, %llu and so on.

Width and setfill('-') in cpp

Here are two other ways to produce this line:

    std::cout << "-------------------------------------\n";

std::setfill + std::setw:

#include <iomanip>

std::cout << std::setfill('-') << std::setw(38) << '\n';

Using a std::string:

#include <string>

std::cout << std::string(37, '-') << '\n';

Demo

How to clear width when outputting from a stream, after using std::setw?

Remember that the input operator >> stops reading at whitespace.

Use e.g. std::getline to get the remainder of the string:

std::stringstream ss("123ABCDEF1And then the rest of the string");
ss >> std::setw(3) >> nId
>> std::setw(6) >> sLabel
>> std::setw(1) >> bFlag;
std::getline(ss, sLeftovers);

Default positioning of fill characters for streams

setfill is defined in [std.manip] as

template<class charT, class traits>
void f(basic_ios<charT, traits>& str, charT c) {
// set fill character
str.fill(c);
}

so we need to look at what happens to an ostream's fill function and that is detailed in [ostream.formatted.reqmts]/3 as

If a formatted output function of a stream os determines padding, it does so as follows. Given a charT character sequence seq where charT is the character type of the stream, if the length of seq is less than os.width(), then enough copies of os.fill() are added to this sequence as necessary to pad to a width of os.width() characters. If (os.flags() & ios_­base​::​adjustfield) == ios_­base​::​left is true, the fill characters are placed after the character sequence; otherwise, they are placed before the character sequence.

So unless left is specified, the fill character come first. By default, left is not a set flag for cout and this is detail in Table 122: basic_­ios​::​init() effects   [tab:basic.ios.cons]

Using the iomanip directive

Unfortunately, no. You must use setw() before almost every output operation. The problem is that operator<< effectively calls setw(0) after the output, thus you need to set width again. See here for a full list of operations that reset field width.

Note: setw is just a wrapper around width(), so using the latter won't help.

Is there a way to set the width of each field at one shot instead of setting every time using streamio?

Iostreams are fickle, and you cannot really rely on the various formatting flags to persist. However, you can use <iomanip> to write things a bit more concisely:

#include <iomanip>
using namespace std;
o << setw(2) << setfill('0') << x;

Modifiers like o << hex and o << uppercase usually persist, while precision and field width modifiers don't. Not sure about the fill character.

printf field width : bytes or chars?

It will result in five bytes being output. And five chars. In ISO C, there is no distinction between chars and bytes. Bytes are not necessarily 8 bits, instead being defined as the width of a char.

The ISO term for an 8-bit value is an octet.

Your "niño" string is actually five characters wide in terms of the C environment (sans the null terminator, of course). If only four symbols show up on your terminal, that's almost certainly a function of the terminal, not C's output functions.

I'm not saying a C implementation couldn't handle Unicode. It could quite easily do UTF-32 if CHAR_BITS was defined as 32. UTF-8 would be harder since it's a variable length encoding but there are ways around almost any problem :-)


Based on your update, it seems like you might have a problem. However, I'm not seeing your described behaviour in my setup with the same locale settings. In my case, I'm getting the same output in those last two printf statements.

If your setup is just stopping output after the first | (I assume that's what you mean by abort but, if you meant the whole program aborts, that's much more serious), I would raise the issue with GNU (try your particular distributions bug procedures first). You've done all the important work such as producing a minimal test case so someone should even be happy to run that against the latest version if your distribution doesn't quite get there (most don't).


As an aside, I'm not sure what you meant by checking the od output. On my system, I get:

pax> ./qq | od -t cx1
0000000 | n i 303 261 o | \n | n i 303 261 | \n
7c 20 6e 69 c3 b1 6f 7c 0a 7c 6e 69 c3 b1 7c 0a
0000020 | A 261 B | \n | A 261 B | \n
7c 41 b1 42 7c 0a 7c 41 b1 42 7c 0a
0000034

so you can see the output stream contains the UTF-8, meaning that it's the terminal program which must interpret this. C/glibc isn't modifying the output at all, so maybe I just misunderstood what you were trying to say.

Although I've just realised you may be saying that your od output has only the starting bar on that line as well (unlike mine which appears to not have the problem), meaning that it is something wrong within C/glibc, not something wrong with the terminal silently dropping the characters (in all honesty, I would expect the terminal to drop either the whole line or just the offending character (i.e., output |A) - the fact that you're just getting | seems to preclude a terminal problem). Please clarify that.



Related Topics



Leave a reply



Submit