__VA_ARGS__的使用

Reference:
1. http://blog.linux.org.tw/~jserv/
2. http://www.jeffhung.net/blog/articles/jeffhung/1013/
3. http://www.cash.idv.tw/wordpress/?p=1531
4. http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html


         __VA_ARGS__是一個可變的marco(Variadic Macros)。為什麼要使用這個功能呢?在code中避免用到太多的#ifndef/#endif,當你的code充滿#ifndef/#endif會讓你的code變得很難閱讀跟理解,所以可以利用__VA_ARGS__跟marco來取代#ifndef/#endif


        當寫程式的過程通常會需要輸出一些訊息,來方便我們Debug。程式會分測試版跟釋出版,所以常常用大量使用#ifndef/#endif,當然使用#ifndef/#endif這種方式也不是不可以,但是就跟剛剛講得code會變得很難閱讀,所以可以多多利用__VA_ARGS__


         首先來瞭解__VA_ARGS__能做什麼。直接看以下的範例,當我定義一個marco叫做DBG(...),括號中的... 。就是說你可以輸入任何的參數,然後就可以用__VA_ARGS__來代表...所傳入的參數。


以下的範例很簡單,當我DEBUG的Flag設定為1,這個時候printf("Hello World\n");才會出現在編譯完的檔案,但這種寫法不是很好,所以只是參考用以方便瞭解__VA_ARGS__

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <stdarg.h>
 
#define DEBUG 1
 
#define DBG(...) \
         if(DEBUG){__VA_ARGS__;}
 
int main(int argc, char *argv)
 {
    DBG(printf("Hello World\n"););
    return 0 ;
}

#Output 


Hello World

        要注意由於__VA_ARGS__是C99新增的功能,所以要確定compiler是否有無支援,需要使用到__STDC_VERSION__ 這個 predefined macro name。接下來範例將會說明:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h> 
#include <stdarg.h>
 
#define DEBUG 1
 
 
#ifdef NDEBUG
#   if (__STDC_VERSION__ < 199901L)
#       error "Please use a newer compiler that support __VA_ARGS__."
#   else
#       define DBG(...) \
            if(DEBUG){__VA_ARGS__;}
#   endif
#else
#   define DBG(...)
#endif
 
int main(int argc, char *argv)
{
    DBG(
        printf("Hello World\n");\
        printf("Test...\n");\
       );  
 
    return 0 ; 
} 

在編譯的指令需要注意如果使用gcc必須加上-std=c99時,編譯才會過還有我也去判斷有沒有NDBUG這個marco有沒有存在,來決定我在編譯的時候是不是要列印出我要的訊息。


gcc -DNDEBUG -std=c99 -o main main.c


gcc -D的定義:


-D name
           Predefine name as a macro, with definition 1


#Output 

Hello World
Test...


但是這種寫法在switch-case會出現有趣的現象,可以參考Reference 1的範例。


因為我也是最近才看到這種用法所以也沒辦法寫的更多,之後有更多的心得再來分享。


以下的範例是從Reference 2來的,我覺得這是一個Debug不錯用的code,如果要更加清楚內容請到原作者的網站看,他說得很清楚,我這邊只是備份以方便我自己以後要用 :p

#include <stdio.h>
#include <stdarg.h>

void dprintf_impl(const char* file, size_t line, int enable, const char* fmt, ...)
{
    va_list ap;
    if (enable) {
        fprintf(stderr, "%s (%d): ", file, line);
        va_start(ap, fmt);
        vfprintf(stderr, fmt, ap);
        va_end(ap);
        fprintf(stderr, "\n");
        fflush(stderr);
    }
}

#ifndef NDEBUG
#   if (__STDC_VERSION__ < 199901L)
#       error "Please use a newer compiler that support __VA_ARGS__."
#   else
#       define DPRINTF(enable, ...) \
               dprintf_impl(__FILE__, __LINE__, enable, __VA_ARGS__)
#   endif
#else
#   define DPRINTF(enable, ...) // define to nothing in release mode
#endif

int main()
{
    int enable = 1;
    int i = 3;
    DPRINTF(enable, "i == %d", i);
    return 0;
}


張貼留言

這個網誌中的熱門文章

解釋scope.$apply用來做什麼? -- AngularJS

Unions 在C語言的簡單介紹

JavaScript的Timer用法