在 GNU C 的 printf 格式规范中正确使用 param-no



我正在开发一个使用printf格式字符串的辅助函数,因此我开始更详细地检查printf格式规范,并发现GNU的手册允许使用param-no: https://www.gnu.org/software/libc/manual/2.36/html_mono/libc.html#Output-Conversion-Syntax.

我以前从未使用过这个功能(因为我觉得它没有用),但是,我希望我的函数能够处理所有可能的格式规范,所以我开始试验它:

#include <stdio.h>
int main()
{
double u = 1.23456789;
double d = 9.87654321;

// Example A                                1.  2. 3.
printf( "A) Testing param-no: >%3$*.*f<n", 12, 3, u );
// Compiler warning: Missing $ operand in format
// Works.

//  // Example B                                1.  2. 3.
//  printf( "B) Testing param-no: >%1$*.*f<n", 12, 3, u );
//  // Compiler warning: Missing $ operand in format
//  // Prints spaces in an infinite loop.

// Example C                                1.  2. 3.
printf( "C) Testing param-no: >%3$*.*f<n", u, 12, 3 );
// Compiler warning: Missing $ operand in format
// Works.

//  // Example D                                1.  2. 3.
//  printf( "D) Testing param-no: >%1$*.*f<n", u, 12, 3 );
//  // Compiler warning: Missing $ operand in format
//  // Prints spaces in an infinite loop.

// Example E                                           1.  2. 3. 4. 5. 6.
printf( "E) Testing param-no: >%3$*.*f<, >%6$*.*f<n", 12, 3, u, 5, 4, d );
// Compiler warning: Missing $ operand in format
// Wrong output: "Testing param-no: >       0.000<, >1.2346<"

// Example F                                           1. 2.  3. 4. 5. 6.
printf( "F) Testing param-no: >%3$*.*f<, >%6$*.*f<n", u, 12, 3, d, 5, 4 );
// Compiler warning: Missing $ operand in format
// Wrong output: "Testing param-no: >       0.000<, >1.2346<"

// Example G                                    1.  2. 3.
printf( "G) Testing param-no: >%3$*1$.*2$f<n", 12, 3, u );
// Works.

// Example H                                                   1.  2. 3. 4. 5. 6.
printf( "H) Testing param-no: >%3$*1$.*2$f<, >%6$*4$.*5$f<n", 12, 3, u, 5, 4, d );
// Works.

// Example I                                                   1. 2.  3. 4. 5. 6.
printf( "I) Testing param-no: >%1$*2$.*3$f<, >%4$*5$.*6$f<n", u, 12, 3, d, 5, 4 );
// Works.

// Example J                                                   1. 2.  3. 4. 5. 6.
printf( "J) Testing param-no: >%4$*5$.*6$f<, >%1$*2$.*3$f<n", u, 12, 3, d, 5, 4 );
// Works.

// Example K                                                   1. 2.  3. 4. 5. 6.
printf( "K) Testing param-no: >%1$*3$.*6$f<, >%5$*2$.*4$f<n", d, 12, 5, 3, u, 4 );
// Works.

return 0;
}

基于这些结果,我发现相关文档中的以下几点具有误导性:

  • 转换规范的第二种一般形式% [ param-no $ ] flags width . * [ param-no $ ] type conversion建议您可以使用星号(*)作为精度,并使用可选的param-no后面跟着一个美元($),就像在例子a中一样。然而,这会生成一个编译器警告,或者像在例子a中一样工作,或者使程序在一个无限的(或者很长,我没有等到它的结尾)循环中打印空格,就像在例子d中一样。

  • 与前一点相关,我正在阅读宽度和精度部件的描述:"您还可以指定字段宽度'*'。这意味着参数列表中的下一个参数(在要打印的实际值之前)被用作字段宽度。">"您还可以指定'*'的精度。这意味着参数列表中的下一个参数(在要打印的实际值之前)用作精度。">,我认为宽度和精度值将从适当的位置获取,这是通过采用实际参数的位置来计算的(例如上述任何示例中的u),并将其减少1或2。但是,这种方法会导致编译器警告和错误输出,如例e所示。

  • 显示转换规范的两种一般形式表明没有第三种形式,您可以得出结论,使用可变参数之一设置宽度是不允许的,因为在第二种一般形式中只有精度部分被星号(*)替换。但是,同时设置宽度和精度的工作方式如下:例h

我怀疑正确的描述如下:

printf模板字符串中的所有转换规范都应该具有下列形式之一,并且所有形式都应具有相同的形式:

% flags [ width-digits | * ] [ . precision-digits | . * ] type conversion

% param-no-a $ flags [ width-digits | * param-no-b $ ] [ . precision-digits | . * param-no-c $ ] type conversion

必选参数param-no-a表示实际参数的位置参数,而可选参数param-no-b和param-no-c表示宽度和精度值的位置。

我链接的文档是正确的吗?

我理解param-no的用法正确吗?

确实,glibc文档似乎是缺乏的。使用man 3p fprintfhttps://pubs.opengroup.org/onlinepubs/9699919799/functions/fprintf.html:

格式可以包含带编号的参数转换规范(即"%n$"one_answers"*m$"),或无编号的参数转换规范(即%和*),但不能同时使用

的格式:

printf("%3$*.*f", 12, 3, 1.23);

是无效的

相关内容

  • 没有找到相关文章

最新更新