簡體   English   中英

在 GNU C 的 printf 格式規范中正確使用 param-no

[英]Correct use of param-no in GNU C's printf format specification

我正在使用 printf 格式字符串開發一個助手 function,所以我開始更詳細地檢查 printf 格式規范,發現 GNU 手冊允許使用參數號: https://www.gnu.org/software/ libc/manual/2.36/html_mono/libc.html#Output-Conversion-Syntax

我以前從未使用過這個功能(因為我沒有發現它有用),但是,我希望我的 function 能夠處理所有可能的格式規范,所以我開始試驗它:

#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 $ ] flags width. * [ param-no $ ] type conversion建議您可以給出一個星號 ( * ) 作為精度和一個可選的 param-no 后跟一個美元 ( $ ),就像示例 A 中那樣。但是,這會生成編譯器警告,並且要么像示例 A 那樣工作,要么像示例 D 那樣使程序在無限(或非常長,我沒有等到它結束)循環中打印空格。

  • 與前一點相關,當我閱讀寬度和精度部分的描述時: “您還可以指定字段寬度為‘*’。這意味着參數列表中的下一個參數(在要打印的實際值之前) ) 用作字段寬度。” “您還可以指定精度為‘*’。這意味着參數列表中的下一個參數(在要打印的實際值之前)用作精度。” ,我認為寬度和精度值將從適當的 position 中獲取,這是通過獲取實際參數的 position(例如上述任何示例中的u )並將其減少 1 或 2 來計算的。但是,這方法會導致編譯器警告和錯誤 output,如示例 E 所示。

  • 呈現轉換規范的兩個通用 forms 表明沒有第三種形式,您可能會得出結論,不允許使用可變參數 arguments 之一設置寬度,因為在第二個中只有精度部分被星號 ( * ) 替換一般形式。 但是,同時設置寬度和精度會像示例 H 中那樣工作。

我懷疑正確的描述如下:

printf 模板字符串中的所有轉換規范都應具有以下 forms 之一,並且它們都應具有相同的形式:

% 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表示實參的position,可選的param-no-b和param-no-c表示寬精度值的position。

我鏈接的文檔是否正確?

我是否正確理解 param-no 的用法?

事實上,似乎缺少 glibc 文檔。 使用man 3p fprintf https://pubs.opengroup.org/onlinepubs/9699919799/functions/fprintf.html

該格式可以包含編號參數轉換規范(即“%n$”和“*m$”)或未編號參數轉換規范(即 % 和 * ),但不能同時包含兩者。

格式:

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

只是無效的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM