You gotta love printf

D

DFS

I wanted to pad a line out to length N (say 25) and add a visual cue,
like so:

Pad this long line to 25 |
Pad this line to 25 |
Pad this to 25 |


So I wrote:

char *padToEnd(const char *lineToPad, char *paddedLine, int lineLen) {
strcpy(paddedLine,lineToPad);
for (int i = 1; i <= (lineLen - (strlen(lineToPad) + 1)); i++) {
strncat(paddedLine, " ", 1);
}
strncat(paddedLine, "|", 1);
return paddedLine;
}


Then I found:

printf("%-*s|\n", lineLen, lineToPad);

where * lets you substitute the value for line length, right into the
printf.

Identical output. Nice!

C is pretty cool... when it's not beating you up.
 
J

Jorgen Grahn

I wanted to pad a line out to length N (say 25) and add a visual cue,
like so:

Pad this long line to 25 |
Pad this line to 25 |
Pad this to 25 | ....
Then I found:

printf("%-*s|\n", lineLen, lineToPad);

where * lets you substitute the value for line length, right into the
printf.

Identical output. Nice!

Yes; people should reread the printf documentation once in a while.
Only recently I discovered that you can make printf truncate strings,
e.g. "%-4.5s".

That one (and the * you mentioned) has enabled me to eliminate a lot
of fragile code which reimplemented the same features.

Printing pointers using %p seems to be another thing a lot of people
are unaware of.

/Jorgen
 
K

Keith Thompson

Jorgen Grahn said:
Printing pointers using %p seems to be another thing a lot of people
are unaware of.

And a lot of people who know about %p don't seem to know that it
specifically requires a void* argument; pointers of other types should
be cast to void*:

int n = 42;
printf("&n = %p\n", &n); // Probably works, but undefined behavior
printf("&n = %p\n", (void*)*n); // Better

(An argument of type char*, signed char*, or unsigned char* will almost
certainly work, but I still prefer the explicit cast; it makes for one
less thing to have to think about.)
 
K

Keith Thompson

Nick Bowler said:
The * feature of printf is a relatively recent addition to the language,
(added in the 1999 revision) and a very useful one. Prior to that you
sometimes see sprintf used to "bake in" the values into a format string
which is then passed to another printf. Using * eliminates a lot of
that pain.
[...]

No, the use of '*' as a field width is included in C89/C90. (It's not
in K&R1.)
 
K

Ken Brody

On 6/12/2014 1:58 PM, Nick Bowler wrote:
[...]
The * feature of printf is a relatively recent addition to the language,
(added in the 1999 revision) and a very useful one. Prior to that you
sometimes see sprintf used to "bake in" the values into a format string
which is then passed to another printf. Using * eliminates a lot of
that pain.
[...]

Yes, I have legacy code with stuff like:

sprintf(formatbuffer,"%%%ds",length);
sprintf(resultbuffer,formatbuffer,string);
 
D

DFS

I wanted to pad a line out to length N (say 25) and add a visual cue,
like so:

Pad this long line to 25 |
Pad this line to 25 |
Pad this to 25 |


So I wrote:

char *padToEnd(const char *lineToPad, char *paddedLine, int lineLen) {
strcpy(paddedLine,lineToPad);
for (int i = 1; i <= (lineLen - (strlen(lineToPad) + 1)); i++) {
strncat(paddedLine, " ", 1);
}
strncat(paddedLine, "|", 1);
return paddedLine;
}


Then I found:

printf("%-*s|\n", lineLen, lineToPad);

where * lets you substitute the value for line length, right into the
printf.

Identical output. Nice!

C is pretty cool... when it's not beating you up.



But, printf will only pad with 0 or space, whereas my little function
can pad with anything:

Pad this long line to 25--|
Pad this line to 25-------|
Pad this to 25------------|

Pad this long line to 25__|
Pad this line to 25_______|
Pad this to 25____________|
 
B

Ben Bacarisse

Ken Brody said:
On 6/12/2014 1:58 PM, Nick Bowler wrote:
[...]
The * feature of printf is a relatively recent addition to the language,
(added in the 1999 revision) and a very useful one. Prior to that you
sometimes see sprintf used to "bake in" the values into a format string
which is then passed to another printf. Using * eliminates a lot of
that pain.
[...]

Yes, I have legacy code with stuff like:

sprintf(formatbuffer,"%%%ds",length);
sprintf(resultbuffer,formatbuffer,string);

Blimey! How old is that code? The * format only just missed being in
K&R1 (1979). It is documented in the V7 man page which seems to be
copyright 1979. I don't think I ever used a C library without it, but I
didn't say hi to C until 1980.
 
J

Jorgen Grahn

Ken Brody said:
On 6/12/2014 1:58 PM, Nick Bowler wrote:
[...]
The * feature of printf is a relatively recent addition to the language,
(added in the 1999 revision) and a very useful one. Prior to that you
sometimes see sprintf used to "bake in" the values into a format string
which is then passed to another printf. Using * eliminates a lot of
that pain.
[...]

Yes, I have legacy code with stuff like:

sprintf(formatbuffer,"%%%ds",length);
sprintf(resultbuffer,formatbuffer,string);

Blimey! How old is that code? The * format only just missed being in
K&R1 (1979). It is documented in the V7 man page which seems to be
copyright 1979. I don't think I ever used a C library without it, but I
didn't say hi to C until 1980.

That was my point upthread: people (myself included) seem to prefer to
write convoluted code like that, to reading the printf manual page.

/Jorgen
 
K

Keith Thompson

Ben Bacarisse said:
Ken Brody said:
On 6/12/2014 1:58 PM, Nick Bowler wrote:
[...]
The * feature of printf is a relatively recent addition to the language,
(added in the 1999 revision) and a very useful one. Prior to that you
sometimes see sprintf used to "bake in" the values into a format string
which is then passed to another printf. Using * eliminates a lot of
that pain.
[...]

Yes, I have legacy code with stuff like:

sprintf(formatbuffer,"%%%ds",length);
sprintf(resultbuffer,formatbuffer,string);

Blimey! How old is that code? The * format only just missed being in
K&R1 (1979). It is documented in the V7 man page which seems to be
copyright 1979. I don't think I ever used a C library without it, but I
didn't say hi to C until 1980.

Quibble: K&R1 was published in 1978.
 
B

Ben Bacarisse

Keith Thompson said:
Quibble: K&R1 was published in 1978.

Yes, thanks. I ended up typing the same date twice. Had I done so
thrice, the whole thing would have been garbled beyond any sense.
 
K

Ken Brody

Ken Brody said:
On 6/12/2014 1:58 PM, Nick Bowler wrote:
[...]
The * feature of printf is a relatively recent addition to the language,
(added in the 1999 revision) and a very useful one. Prior to that you
sometimes see sprintf used to "bake in" the values into a format string
which is then passed to another printf. Using * eliminates a lot of
that pain.
[...]

Yes, I have legacy code with stuff like:

sprintf(formatbuffer,"%%%ds",length);
sprintf(resultbuffer,formatbuffer,string);

Blimey! How old is that code? The * format only just missed being in
K&R1 (1979). It is documented in the V7 man page which seems to be
copyright 1979. I don't think I ever used a C library without it, but I
didn't say hi to C until 1980.

Well, it's not in any "recent" code, but I have seen it in code that's been
around since TRS-Xenix on the Tandy Model 16. (ie: early 1980's.) It
wasn't in K&R1, and it might not have been in the TRS-Xenix manuals, either.
 
B

Ben Bacarisse

Ken Brody said:
Well, it's not in any "recent" code, but I have seen it in code that's
been around since TRS-Xenix on the Tandy Model 16. (ie: early
1980's.) It wasn't in K&R1, and it might not have been in the
TRS-Xenix manuals, either.

The TRS-Xenix manual does have it, but code gets copied about so it may
well pre-date Xenix. And there's always that point that people just
don't read manuals.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,731
Messages
2,569,432
Members
44,832
Latest member
GlennSmall

Latest Threads

Top