2013-02-14 71 views
2

讓我解釋一下這種情況: 我有一個C結構如下:如何使用具有自適應類型的printf()函數?

typedef struct { 
    int *val; 
    char *name; 
} tStruct; 

這種結構可能會被填充如下: - VAL可以爲空,如果「VAL」值不可用,否則VAL是一個整數值(可以是負數) - 名稱不可用時,名稱可以是空字符串,如果名稱可用,名稱可以是填充字符串(此處不爲空指針)。

我希望寫一個日誌行如下:

  • 如果val是無效的,名稱是有效的(等於WOOT):

LOG VAL =#NAME = WOOT

  • 如果val無效,名稱無效:

LOG VAL =#NAME =#

  • 如果val是有效的,名稱是無效的:

LOG VAL = 123456名=#

  • 如果val有效,名稱有效(等於WOOT):

LOG VAL = 123456名= WOOT

這意味着我需要爲使用的printf( 「VAL =%s的名稱=%s」 時,...)或printf(「val =%d name =%s」,...),這取決於id值(這樣我可以輸出一個#或整數)。當val無效時輸出一個假整數值是不合適的,因爲任何有符號或無符號的值都是可能的。

有什麼想法?我希望我能避免以下類型的結構,因爲我的結構實際上將包含許多領域,使得太多的「如果」組合:

if ((struct.val == NULL) && (struct.name)) then printf ("val=# name=%"); 
else if ((struct.val == NULL) && (! struct.name)) then printf ("val=# name=#"); 
else if ... 

謝謝

+0

我不認爲你的意思是'%#',那應該只是一個普通的'#',即沒有格式說明符。 – unwind 2013-02-14 09:58:42

+0

是的,你對此感到抱歉。更正了,謝謝指出! – SCO 2013-02-15 14:27:14

回答

2
printf("LOG val="); 
if (struct.val) printf("%d", *struct.val); else printf("#"); 
printf(" name="); 
if (*struct.name) printf("%s", struct.name); else printf("#"); 
printf("\n"); 
3

創建一個返回的功能該類型的字符串表示,然後用它在printf中

printf("%s", tStruct_to_string(contents)); 

注意,它可能很難用這種方式 ,除非你的轉換函數有這麼我靜態緩衝區。

編輯:這裏使用單個靜態緩衝區是錯誤的,因爲它不適用於多個參數。正如@pmg所說的,接受一個緩衝區更好,但是會有緩衝區溢出的風險,所以也許你可以將長度作爲參數傳遞,但現在優雅的解決方案並沒有像以前那麼優雅。所以,你的函數可以返回malloced char *,但是之後你可以釋放它,動態分配可能會很慢。 Ufff ...在C中管理字符串是相當痛苦的。

現在我可以考慮的最佳方式(但它受到重入問題的影響)是使用靜態數組的字符串並在每個調用中循環。

char* tStruct_to_string(tStruct st) 
{ 
    /* 
    * here assuming no one will call printf 
    * with more than 32 arguments of this type, 
    * and assuming length of string 100. 
    */ 
    static char strings[32][100]; 
    static int next = 0; 
    int current = next; 
    // here you write to strings[current] 
    // use s(n)printf for writing to string 
    next = (next+1)%32; 
    return strings[current]; 
} 

此外,其他答案提供了很好的建議如何避免重複的條件。

+0

+1:目前爲止的最佳解決方案。我寫函數接受一個緩衝區,並返回相同的緩衝區:'printf(「%s」,tStruct_to_string(buffer,contents));' – pmg 2013-02-14 10:06:18

1

對於你必須使用一個if語句,輸出是一個字符串或一個數val成員,但對於name你可以使用ternary expression

if (str.val) 
    printf("val=%d name=%s", *str.val, *str.name == '\0' ? "#" : str.name); 
else 
    printf("val=# name=%s", *str.name == '\0' ? "#" : str.name); 
1

如果你的結構有許多這樣的對,顯而易見的是將打印的一個對分成一個函數,然後在真實結構中調用它。

void print_pair(const int *value, const char *name) 
{ 
    if(value == NULL && name == NULL) 
     printf("val=# name=#"); 
    else if(value == NULL && name != NULL) 
     printf("val=# name=%s", name); 
    else if(value != NULL && name == NULL) 
     printf("val=%d name=#", *value); 
    else 
     printf("val=%d name=%s", *value, name); 
} 

您可以通過使用一個事實,即#可表示爲一個字符串,也縮短了上面。

你可以把它甚至通過分解出的想法,整數轉換成字符串兩種方式較短,但可能是過度做它:

void print_pair(const int *value, const char *name) 
{ 
    char vbuf[32]; 

    if(value == NULL) 
     strcpy(vbuf, "#"); 
    else 
     snprintf(vbuf, sizeof vbuf, "%d", *value); 

    printf("val=%s name=%s", vbuf, name != NULL ? name : "#"); 
} 
1

爲什麼要經歷這些努力將所有東西壓縮到一個printf調用中?只需調用兩次。

if (s.val) 
    printf("val=%d ", *s.val); 
else 
    printf("val=# "); 
printf("s.name=%s", s.name ? *s.name : "#"); 
相關問題