我正在开发一个使用printf格式字符串的helper函数,因此我开始更详细地检查printf格式规范,并发现GNU手册允许使用param-no:www.example.com网站。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的用法?
1条答案
按热度按时间9o685dep1#
实际上,glibc文档似乎缺乏。使用
man 3p fprintf
https://pubs.opengroup.org/onlinepubs/9699919799/functions/fprintf.html:格式可以包含编号参数转换规范(即“%n$”和“*m$”),也可以包含未编号参数转换规范(即%和 *),但不能同时包含两者。
格式:
是无效的。