如何在C语言的printf函数中传递参数

6

假设我有一个带有多个参数的 printf:

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

由于某些原因,我希望其中一个参数不再被打印,但仍应列在参数列表中(例如出于视觉原因,或者它是具有必要副作用的函数调用等)。

我能否用无输出的转换字符替换%d?我不记得有这样的转换字符。或者也许可以尝试修改标志...?

[编辑] 我刚注意到scanf有类似的功能(但相反):赋值抑制标志'*',例如sscanf("123 345 678", "%i %*i %i", &a, &b)将导致a=123 b=678


9
也许这是一个带有必要副作用的函数调用。嗯,不要这样做,参数的求值顺序未指定(即:随机)。你可以尝试通过将某些值的打印大小设置为0来“跳过”它们。 - Radosław Cybulski
能否使用格式的宽度来隐藏打印输出?例如打印一个定长为0的数字?我认为只能指定最小宽度而不能指定最大宽度,但这是一个有趣的用例。 - geckos
3
*printf 没有输出抑制修饰符,您需要删除不想打印的内容。 - John Bode
请不要这样做。将来你或者你的同事会阅读到这个并且会完全困惑为什么有人会写这个。 - schorsch312
4
顺序计算?printf("%d %d %d", A, (B, C), D);(省略了B的结果)? - chux - Reinstate Monica
3个回答

12
如果您非常必须即时更改这些内容,那么请保持简单:
printf("%d ", A);
printf("%d ", B);
if(c) 
  printf("%d ", C);
printf("%d ", D);

如果将输出打印到共享输出(例如STDOUT)上,可能会出现意外行为,因为另一个进程/线程等可能会在两个printf之间打印一些内容。 - hippietrail
@hippietrail 我不会假设 printf 是线程安全的。我猜POSIX可能会提供这样的保证。但是从多个线程中打印输出是非常糟糕的程序设计,你应该将所有打印输出外包给专门的打印/ GUI 线程。 - Lundin

2

您可以通过指定零宽度来抑制字符串(char*)参数。

然而,我不知道如何抑制数字(intfloat)值。

原始答案:Original Answer

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;
}

1
首先,我同意Radosław Cybulski的评论:依赖副作用是一件危险的事情。因此,请不要这样做。
至于抑制参数的打印,我认为没有内置的占位符,最好的方法可能是注释掉整个printf语句,并在其下方添加没有被抑制的版本。
话虽如此,我想到了两种(不太优雅的)解决方案,可以实现类似于您想要实现的功能:

方法1

您可以创建一个宏,如下所示: #define SUPPRESS_PRINT(x) "\0"/*x*/ 这将使用空终止字符替换参数。
然后,您可以像这样在printf语句中使用它: printf("%d %d %s %d", A, B, SUPPRESS_PRINT(C), D); 请注意,C的占位符(即被抑制的参数)必须更改为%s,这是一个空终止字符串,以便这个“技巧”产生所需的结果。
更正:

感谢评论区jhx提供的绝妙建议,我已经完善了上述解决方案。使用顺序评估可以避免遗漏可能的副作用。修订后的宏如下:

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

使用方式与上述描述相同。


方法2

还有另一种可能更简单的解决方法。它是一个POSIX特性而不是C99特性,但我认为它在大多数情况下都能起作用。就是在每个格式占位符中使用参数字段。类似于这样:

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

如果您想从输出中省略参数C,只需从格式字符串中删除%3$d即可。因此,得到以下内容:
printf("%1$d %2$d %4$d", A, B, C, D);

这可能是最简单的方法。

工作原理:参数字段将格式占位符与给定参数绑定,使用其序号。因此,即使您删除一个,其余部分仍将正确打印。

注意:据我测试,此方法不会省略副作用!


C是一个带有副作用的表达式时,这种方法无法工作,因为你已经将该表达式注释掉了。 - rtoijala
2
这与我刚刚提交的答案非常相似,所以我将删除我的答案。但是,你不需要使用 "\0",因为 "" 已经足够了。为了使参数得到求值,你可以通过使用 , 扩展宏来包含该参数,如 ((x), "") - jxh
@jxh 那个顺序评估的解决方案真是太棒了!感谢你的更正。 - Istvan Balogh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接