2015-11-03 68 views
2

它發生在我身上多次與float一起工作的變量必須printf這些變量正確地格式化爲一定數量的小數位。我知道,在C可以使用下面的符號來指定十進制和總位數輕易格式化float變量:C中的多個動態浮點格式說明符

// Where x and y are natural numbers 
printf("%<x>.<y>f", myFloat); 

而且我也知道,你可以使用兩個變量,使用*符號dynamically format a float這樣:

// Where x and y are natural numbers 
printf("%*.*f", x, y, myFloat); 

我最近陷入了一個真正的冗餘情況:當我有相同的動態格式printf出多個float號碼我必須重複這兩個xy變量幾千次。我總是喜歡#define我的常量,這樣我可以很容易地在未來改變他們,所以我的計劃是這樣:

#define FLOAT_FORMAT_SIZE 10 
#define FLOAT_FORMAT_PRECISION 3 

int main(int argc, char *argv[]) { 
    // Anything I have to do... 

    // Output 
    printf("%*.*f, %*.*f, %*.*f, %*.*f", 
     FLOAT_FORMAT_SIZE, FLOAT_FORMAT_PRECISION, myFloat1, 
     FLOAT_FORMAT_SIZE, FLOAT_FORMAT_PRECISION, myFloat2, 
     FLOAT_FORMAT_SIZE, FLOAT_FORMAT_PRECISION, myFloat3, 
     FLOAT_FORMAT_SIZE, FLOAT_FORMAT_PRECISION, myFloat4 
    ); 

    return 0; 
} 

現在你可以看到這是一個有點過於冗餘,我是想知道:是不是有任何特殊的系統常量或格式技術,我可以用來避免重複相同的值一遍又一遍每floatprintf出?

我不想創建自己的函數來打印出這些數字,我可以明顯地做到這一點,但如果可能的話,我想在較低的級別上解決它。

+2

在運行時動態創建格式字符串 - 就像任何其他字符串一樣。 – chux

回答

2

您可以編寫定義打印的默認方式宏浮動:

#define FLOAT_FORMAT_SIZE 10 
#define FLOAT_FORMAT_PRECISION 3 

#define M_STR(x) M_STR_(x) 
#define M_STR_(x) #x 

#define FLOAT_FMT      \ 
    "%" M_STR(FLOAT_FORMAT_SIZE)  \ 
    "." M_STR(FLOAT_FORMAT_PRECISION) \ 
    "f" 

然後你printf聲明將是這樣的:

printf(FLOAT_FMT ", " FLOAT_FMT ", " FLOAT_FMT ", " FLOAT_FMT, 
    myFloat1, myFloat2, myFloat3, myFloat4); 

宏觀和如何用於使用字符串文字串聯。格式字符串是在編譯時創建的,因此會觸發有關格式和參數類型不匹配的警告。

當然,格式化字符串是否可讀性是值得商榷的。

編輯:這是如何工作的?宏M_STR「串化」它的論點;它將它變成一個C字符串文字。宏定義中可用的運算符#可以實現此目的。

必須使用輔助宏的間接尋址M_STR_,以便首先擴展宏參數。沒有這個輔助宏,M_STR(FLOAT_FORMAT_SIZE)將被擴展爲"FLOAT_FORMAT_SIZE"。通過M_STR_繞道,宏FLOAT_FORMAT_SIZE在變成一個字符串之前被展開,結果字符串是"10"

因此,宏FLOAT_FMT擴展到

"%" "10" "." "3" "f" 

C編譯器會連接相鄰的字符串常量,所以宏的最終結果等於"%10.3f"

同樣正在建設中的格式字符串時做到:

printf(FLOAT_FMT ", " FLOAT_FMT ", " FLOAT_FMT ", " FLOAT_FMT, 
    myFloat1, myFloat2, myFloat3, myFloat4); 

是有效的:

printf("%10.3f, %10.3f, %10.3f, %10.3f", 
    myFloat1, myFloat2, myFloat3, myFloat4); 

這一解決方案的缺點是字符串和宏並列有點難以閱讀。

+0

你能更精確地解釋第一個被剪下的代碼嗎?我不認爲我能理解這一切。 –

+0

@MarcoBonelli:我添加了一個解釋。 –

2

您可以在運行時創建格式字符串並根據需要多次使用它。

// Create the format string. 
char formatString[100]; // Make it large enough. 
sprintf(formatString, "%%%d.%df", FLOAT_FORMAT_SIZE, FLOAT_FORMAT_PRECISION); 

// Use the format string to print a float 
printf(formatString, myFloat1); 
printf(formatString, myFloat2); 
printf(formatString, myFloat3); 
printf(formatString, myFloat4); 
+0

不知道'sprintf',聽起來很酷......謝謝! –