繁体   English   中英

一个Abstrusing printf()表达式

[英]An Abstrusing printf() expression

在阅读一些随机代码时,我碰巧遇到了一个对我来说有点奇怪的printf()表达式,语句是这样的

void PrintDiceFace(int n){
    printf("%d 0 %d\n%d %d %3$d\n%2$d 0 %1$d\n\n",n>50,51%n%2,n>53,n%2);
}

这实际上是模糊的片段版本,它实际上打印了电子骰子的面部。 例如

请详细解释这个printf()语句。

http://en.wikipedia.org/wiki/Dice

POSIX / SUS printf()允许一个数字,后跟$% ,以表明从可变参数的特定参数应该是采摘。

printf("%2$s, %1$s!\n", "world", "Hello");

格式导致:

<num1>    0   <num2>
<num3> <num4> <num3>
<num2>    0   <num1>

所有数字都是0或1,具体取决于稍后的操作结果。 这个格式字符串中唯一不寻常的是使用%<N>$ - 这表示对于这个参数,应该使用函数的arg<N> (而不是按顺序的“下一个”)。 例如,如果您指定:

printf("%d %1$x\n", 10);

它打印你'10 a'。

它打印三行整数,比如更简单:

printf("%d %d %d\n%d %d %d\n%d %d %d\n", 0, 0, 0, 0, 1, 0, 0, 0, 0);

哪个会打印

0 0 0
0 1 0
0 0 0

%2 $ d表示“使用第二个参数而不是与我的位置对应的参数”

现在,每行中的每列都有一个特定条件,在该点上打印“0”或“1”。 由于骰子的对称性,你真正感兴趣的是以下位置(用x标记):

x 0 x
x x -
- 0 -

其他位置可以从它们( - )导出或始终为0(0)。

这是“聪明的编码”的一个例子,这很有趣,但阅读令人沮丧。

让我们从格式开始( "%d 0 %d\\n%d %d %3$d\\n%2$d 0 %1$d\\n\\n" ):

  • %d表示数字(十进制数作为整数)输出
  • %3d表示您允许至少3个字符作为输出的占位符(因此例如“2”将填充“2”。您可以使用%03d执行相同操作但使用前导零填充以获取“00”)
  • %3 $ d实际上意味着不是以适当的顺序使用列表中的元素,而是直接指定元素(所以这里它将是n > 53
  • 等等...

对于看起来很滑稽的参数:

  • n> 50将是第1和第7%d
  • 51%n%2将是第2和第6%d
  • n> 53将是第3和第5%d
  • n%2将是第4%d

man 3 printf

此代码不一致且已损坏。 如果使用%N$ -type参数索引说明符,则必须将它们用于所有参数,而不是选择性地用于某些参数而不是其他参数。

固定版本:

printf("%1$d 0 %2$d\n%3$d %4$d %3$d\n%2$d 0 %1$d\n\n",n>50,51%n%2,n>53,n%2);

相关引文如下: http//www.opengroup.org/onlinepubs/9699919799/functions/fprintf.html

格式可以包含编号参数转换规范(即“%n $”和“* m $”),或无编号参数转换规范(即%和*),但不能同时包含两者。 唯一的例外是%%可以与“%n $”表单混合使用。 在格式字符串中混合编号和未编号参数规范的结果是未定义的。 当使用带编号的参数规范时,指定第N个参数要求在格式字符串中指定从第一个到第(N-1)个的所有前导参数。

这段代码“工作”的事实是printf函数的特定实现(可能是GNU函数)的副作用。 没有理由期望它在其他系统上工作,甚至在同一系统的未来版本上工作,除非它被记录在该系统上工作。

即使使用我的修复程序,此代码仍然是POSIX特定的; 它不能移植到非POSIX系统上的C实现。 而不是丑陋的黑客,作者应该根据需要复制参数:

printf("%d 0 %d\n%d %d %d\n%d 0 %d\n\n",n>50,51%n%2,n>53,n%2,n>53,51%n%2,n>50);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM