Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to swallow a parameter in printf in C

Tags:

c

printf

Say I have a printf with many parameters:

printf("%d %d %d %d", A, B, C, D);

For some reason I would like one parameter to no longer be printed, but still be listed in the parameter list (for instance for visual reason, or maybe it's a function call with a necessary side effect, etc).

Can I replace %d with a conversion letter with no output ? I don't recall such a conversion letter. Or maybe playing with the flags...?

[Edit] I just noticed that scanf has something similar (but the reverse): an assignment suppression flag '*'. for instance sscanf("123 345 678", "%i %*i %i", &a, &b) will lead to a=123 b=678

like image 271
dargaud Avatar asked Jun 17 '19 13:06

dargaud


Video Answer


3 Answers

If you for some reason must change these on the fly, then keep things simple:

printf("%d ", A);
printf("%d ", B);
if(c) 
  printf("%d ", C);
printf("%d ", D);
like image 63
Lundin Avatar answered Oct 19 '22 10:10

Lundin


You can suppress Strings (char*) arguments by specifying zero-width.

However, I know of no way to suppress numeric (int and float) values.

int main(void) {
    int a=1;
    char*  b="hello";  // Gets Suppressed
    int c=3;

    printf("%d %.0s %d\n", a, b, c); // .0 means "zero-width"
    return 0;
}
like image 27
abelenky Avatar answered Oct 19 '22 11:10

abelenky


First of all, I agree with Radosław Cybulski's comment: Relying on side-effects is a dangerous thing. So please don't do that.

As for suppressing the printing of a parameter I think there is no built-in placeholder for that and it would probably be better to just comment out the whole printf statement and add the version without the suppressed parameter below it.

With that said there are two(not very elegant) solutions I could come up with that does something similar to what you'd like to achieve:

Method1

You could create a macro like this:

#define SUPPRESS_PRINT(x) "\0"/*x*/

This will replace the parameter with a null terminator character.

Then you can use it in your printf statement like this:

printf("%d %d %s %d", A, B, SUPPRESS_PRINT(C), D);

Notice that the placeholder for C (i.e. the suppressed parameter) had to be changed to %s that is a null terminated string in order for this "trick" to yield the desired result.

Correction:

I've enhanced the above solution thanks to jhx's awesome suggestion in the comments. Using sequential evaluation possible side-effects won't be omitted. The revised macro would look like this:

#define SUPPRESS_PRINTF_ARG(x) ((x), "")

Usage would stay the same as described above.


Method2

There is yet another, possibly simpler, solution. It is a POSIX feature not a C99 one but it would work in most scenarios I assume. It is to use a parameter field in each format placeholder. Something like this:

printf("%1$d %2$d %3$d %4$d", A, B, C, D);

Then if you'd want to omit let's say parameter C from being printed you could just delete %3$d from the format string. Thus getting this:

printf("%1$d %2$d %4$d", A, B, C, D);

This might be the simplest way to go about it.

Working principle: The parameter field ties the format placeholder to a given parameter using its ordinal number. Thus even if you remove one the rest will still print correctly.

Note: As far as my testing goes this method does not omit side-effects!

like image 44
Istvan Balogh Avatar answered Oct 19 '22 09:10

Istvan Balogh