2012-06-12 82 views
0

我已經試過這樣:如何寫一個做malloc的宏,格式化一個字符串,然後返回格式化的字符串?

#define format(f, ...) \ 
       int size = strlen(f) + (sizeof((int[]){__VA_ARGS__})/sizeof(int)) + 1); \ 
       char *buf = malloc(size); \ 
       snprintf(buf, size, f, __VA_ARGS__); \ 
       buf 

但它返回了很多語法錯誤的。我如何正確地做到這一點?

+2

我能插一句說,你真的不應該比學習如何在C預作品以外的任何理由這樣做呢? – djechlin

+1

..還寫下你得到的確切的錯誤? – 2012-06-12 15:13:55

回答

3

C宏不是函數,而是1:1替換。所以,如果你想使用您的宏是這樣的:

mystring = format("%d", 5); 

你得到這樣的:

mystring = int size = strlen(f) + (sizeof((int[]){5})/sizeof(int)) + 1); \ 
      char *buf = malloc(size); \ 
      snprintf(buf, size, f, 5); \ 
      buf; 

不使任何意義。在你的情況下,你最好定義一個內聯函數,它在一個體面的編譯器上的性能應該不會更糟。

如果它真的必須是一個宏,你在GCC上,你可以使用複合語句來實現你的目標。它允許你這樣做:mystring = ({ statement1, statement2, ..., statementN})它將在本地範圍內執行你所有的語句,然後分配statementNmystring。但是,它會使你的代碼不可移植並且很難調試。

所以在這裏你走了,但請不要在實際應用中使用:

#define format(f, ...) \ 
    ({ int size = snprintf(NULL, 0, f, __VA_ARGS__) + 1;\ 
    char * buf = malloc(size);\ 
    snprintf(buf, size, f, __VA_ARGS__); buf; }) 

我是認真的。不要使用這個。使用內聯函數。您也可以在正常功能可變參數,使用va_argva_start

inline char * format(f, ...) { 
    va_list args; 
    va_start(args, f); 
    int size = vsnprintf(NULL, 0, f, args) + 1; 
    char * buf = malloc(size); 
    vsnprintf(buf, size, f, args); 
    return buf; 
} 
0

如果使用此不帶參數,應鍵入

snprintf(buf, size, f, ## __VA_ARGS__); 

代替;否則它不會截斷尾隨逗號。

此外,如果您想使用格式字符串,您不能確定strlen(format) + length of every other elements實際上是您獲得的大小。你必須做一個假設,然後使用安全的功能。

使用這種宏語法返回值也是不可能的。然而,使用GNU擴展也是可能的。請參閱下面的修改答案。

而且,你想要什麼用

sizeof((int[]){__VA_ARGS__} 

辦?這根本不好。您無法找到可變參數列表的大小。

嘗試這樣:

#define format(f, ...) \ 
      ({ 
      char *buf = malloc(4096); \ 
      snprintf(buf, 4096, f , ## __VA_ARGS__); \ 
      buf 
     }) 

希望這有助於。

+0

OP的代碼有比這個更大的問題,並且你的代碼甚至不是有效的C .. –

+0

什麼是無效的? – 2012-06-12 15:21:29

+0

您在這裏使用了幾個gcc擴展。該OP沒有說特定的編譯器 –

0

不知道你想要做的第一行。你似乎試圖計算參數的數量,但是你將它傳遞給malloc並使用返回值malloc作爲大小。?!

snprintf分配空間的正確方法是首先調用snprintf,緩衝區指針和大小爲零,然後檢查返回值。給返回值加上一個(用於空終止)會給你分配的大小,並傳遞給第二個snprintf調用。

另外,不要試圖用宏來做到這一點;使用功能和vsnprintf