Ignore argument to 'printf'?

  • Thread starter Arthur J. O'Dwyer
  • Start date
A

Arthur J. O'Dwyer

I have a situation where I want to use one of two different format
strings in a 'printf' call, depending on a flag set by the user.
One of the calls uses a field width modifier, and the other one doesn't.
So what I have at the moment is

if (UserFlag) {
printf("%*d. ", clue_width, clue_number);
}
else {
printf("%d.\t", clue_number);
}

What I'd like to have is

const char *clue_format = (UserFlag? "%*d. ": [...something...]);
printf(clue_format, clue_width, clue_number);

Problem is, I don't see any way to tell 'printf' to simply discard
its second argument. "%0.0d" doesn't work; according to the standard,
'printf' will never truncate its output, even given a zero field width.
So, can anyone think of what my [...something...] should be?
Failing that, can anyone think of a method shorter and cleaner than
the method outlined above?

Thanks,
-Arthur
 
W

Walter Roberson

I have a situation where I want to use one of two different format
strings in a 'printf' call, depending on a flag set by the user.
Problem is, I don't see any way to tell 'printf' to simply discard
its second argument.

printf() stops converting when it reaches the end of its format
string, ignoring any argument that has not been converted.

(It helps to remember printf()'s antecedants, in the days when
there was no way to tell how many arguments had been given to
a varadic call, so the only way that printf() had of knowing
there -were- more arguments was to hit another format specifier.)
 
D

dot

Problem is, I don't see any way to tell 'printf' to simply discard
its second argument.

printf("%d\n",1,2,3);

prints 1 on my screen.

The arguments that aren't matched in the formatting string, are simply
ignored.
 
A

Arthur J. O'Dwyer

I have a situation where I want to use one of two different format
strings in a 'printf' call, depending on a flag set by the user.
One of the calls uses a field width modifier, and the other one doesn't.
So what I have at the moment is

if (UserFlag) {
printf("%*d. ", clue_width, clue_number);
}
else {
printf("%d.\t", clue_number);
}

I see I've gotten two "non-answers" already. In case it wasn't
clear, I'm looking for solutions to the setup above, not to

if (UserFlag) {
printf("%*d. ", a, b);
}
else {
printf("%d.\t", a);
}

HTH,
-Arthur
 
C

Chris Torek

[edited slightly for vertical space]

I see I've gotten two "non-answers" already. In case it wasn't
clear, I'm looking for solutions to the setup above, not to
if (UserFlag) printf("%*d. ", a, b);
else printf("%d.\t", a);

Indeed, in this case the "ignores extra, unused arguments" feature
of printf() is not helpful, because we need the "clue_width"
argument to disappear.

There are a couple of possible approaches. One, which I will
mention just because it is horrendously ugly and nonportable but
chances are it works on your ILP32 machine, is to misuse the "%n"
conversion specifier and assume that sizeof(int) == sizeof(int *):

if (UserFlag) {
fmt = "%*d. ";
arg1 = clue_width;
} else {
fmt = "%n%d.\t";
arg1 = (int) &clue_width;
}
...
printf(fmt, arg1, clue_number);

Of course, this potentially breaks as soon as you move to an I32LP64
machine (where sizeof(int) is 4 but sizeof(int *) is 8). There
are even worse hacks to work around that, in various even-more-
machine-dependent ways, but this whole thing is a bad idea.

So what else can we do? Well, observe that printf's output for
"%d" and "%1d" is always 100% identical:

printf("(plain) d: [%d] [%d] [%d]\n", 0, 1, 99);
printf("width 1d: [%1d] [%1d] [%1d]\n", 0, 1, 99);

The output here is always "[0] [1] [99]": specifying a minimum
field width of 1 has no effect because %d always produces at least
one output character. So now the answer is obvious:

if (UserFlag) {
fmt = "%*d. ";
/* and use specified clue_width */
} else {
fmt = "%*d.\t";
clue_width = 1;
}
...
printf(fmt, arg1, clue_number);

(In fact, %*d with an integer value of -1 also works. Using 0
works in my printf, but I think the Standard does not say just
what happens in this case.)
 
W

Walter Roberson

I see I've gotten two "non-answers" already.

Sorry, I misread the "second argument" as "last argument".

I do not have my copy of the standard here to check the
portability of the below... I -remember- this as being part
of the standard (not just as a local extension on the system I'm
checking), but YMMV.

printf( UserFlag? "%*d. " : "%2$d.\t", clue_width, clue_number );

posp$ An optional entry, consisting of one or more decimal digits
followed by a $ character, specifying the number of the next arg to
access. The first arg (just after format) is numbered 1. If this
field is not specified, the arg following the most recently used
arg will be used.
 
P

Peter Nilsson

Walter said:
I do not have my copy of the standard here to check the
portability of the below... I -remember- this as being part
of the standard (not just as a local extension on the system I'm
checking), but YMMV.

printf( UserFlag? "%*d. " : "%2$d.\t", clue_width, clue_number );

posp$ An optional entry, consisting of one or more decimal
digits followed by a $ character,...

The $ character is not a member of the basic character set in C.
[Aside: neither is @ unfortunately.]

It may well be standardised usage, but it is not C standard usage.
 
A

Arthur J. O'Dwyer

if (UserFlag) {
fmt = "%*d. ";
/* and use specified clue_width */
} else {
fmt = "%*d.\t";
clue_width = 1;
}
...
printf(fmt, arg1, clue_number);

...Of course! Argh! Thank you. I hadn't been thinking of modifying
'clue_width', but actually there's no reason not to.

-Arthur
 
E

Eric Sosman

Arthur said:
I have a situation where I want to use one of two different format
strings in a 'printf' call, depending on a flag set by the user.
One of the calls uses a field width modifier, and the other one doesn't.
So what I have at the moment is

if (UserFlag) {
printf("%*d. ", clue_width, clue_number);
}
else {
printf("%d.\t", clue_number);
}

I see I've gotten two "non-answers" already. [...]

What you're using seems perfectly reasonable and not
worth changing (unless surrounding context provides reasons
of its own). You could try

printf(UserFlag ? "%*d. " : "%*d\t", /* note change */
UserFlag ? clue_width : 0,
clue_number);

.... but to my eye this doesn't look like an improvement.
 
J

Joe Wright

Arthur said:
...Of course! Argh! Thank you. I hadn't been thinking of modifying
'clue_width', but actually there's no reason not to.

-Arthur

Try this..

#include <stdio.h>

int main(void) {
char *format = "%*d.\n ";
int width = 10;
int number = 23;
printf(format, width, number);
width = 0;
printf(format, width, number);
return 0;
}
 
D

Dave Thompson

On 2 Apr 2005 20:54:34 GMT, (e-mail address removed)-cnrc.gc.ca (Walter
Roberson) wrote:
I do not have my copy of the standard here to check the
portability of the below... I -remember- this as being part
of the standard (not just as a local extension on the system I'm
checking), but YMMV. <snip printf %position$specifier>

It's POSIX-standard (not just local) but not C-standard.

- David.Thompson1 at worldnet.att.net
 

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

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top