• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            colorful

            zc qq:1337220912

             

            c++ 宏

            c/c++ 宏中"#"和"##"的用法
            2007年05月14日 星期一 上午 10:19
            一、一般用法
            我們使用#把宏參數變為一個字符串,用##把兩個宏參數貼合在一起.
            用法:
            #i nclude<cstdio>
            #i nclude<climits>
            using namespace std;
            #define STR(s)      #s
            #define CONS(a,b)   int(a##e##b)

            int main()
            {
                 printf(STR(vck));            // 輸出字符串"vck"
                 printf("%d\n", CONS(2,3));   // 2e3 輸出:2000
                 return 0;
            }

            二、當宏參數是另一個宏的時候
            需要注意的是凡宏定義里有用'#'或'##'的地方宏參數是不會再展開.

            1, 非'#'和'##'的情況
            #define TOW       (2)
            #define MUL(a,b) (a*b)

            printf("%d*%d=%d\n", TOW, TOW, MUL(TOW,TOW));
            這行的宏會被展開為:
            printf("%d*%d=%d\n", (2), (2), ((2)*(2)));
            MUL里的參數TOW會被展開為(2).

            2, 當有'#'或'##'的時候
            #define A           (2)
            #define STR(s)      #s
            #define CONS(a,b)   int(a##e##b)

            printf("int max: %s\n",   STR(INT_MAX));     // INT_MAX #i nclude<climits>
            這行會被展開為:
            printf("int max: %s\n", "INT_MAX");

            printf("%s\n", CONS(A, A));                // compile error
            這一行則是:
            printf("%s\n", int(AeA));

            INT_MAX和A都不會再被展開, 然而解決這個問題的方法很簡單. 加多一層中間轉換宏.
            加這層宏的用意是把所有宏的參數在這層里全部展開, 那么在轉換宏里的那一個宏(_STR)就能得到正確的宏參數.

            #define A            (2)
            #define _STR(s)      #s
            #define STR(s)       _STR(s)           // 轉換宏
            #define _CONS(a,b)   int(a##e##b)
            #define CONS(a,b)    _CONS(a,b)        // 轉換宏

            printf("int max: %s\n", STR(INT_MAX));           // INT_MAX,int型的最大值,為一個變量 #i nclude<climits>
            輸出為: int max: 0x7fffffff
            STR(INT_MAX) -->   _STR(0x7fffffff) 然后再轉換成字符串;

            printf("%d\n", CONS(A, A));
            輸出為:200
            CONS(A, A)   -->   _CONS((2), (2))   --> int((2)e(2))

            三、'#'和'##'的一些應用特例
            1、合并匿名變量名
            #define   ___ANONYMOUS1(type, var, line)   type   var##line
            #define   __ANONYMOUS0(type, line)   ___ANONYMOUS1(type, _anonymous, line)
            #define   ANONYMOUS(type)   __ANONYMOUS0(type, __LINE__)
            例:ANONYMOUS(static int);   即: static int _anonymous70;   70表示該行行號;
            第一層:ANONYMOUS(static int);   -->   __ANONYMOUS0(static int, __LINE__);
            第二層:                         -->   ___ANONYMOUS1(static int, _anonymous, 70);
            第三層:                         -->   static int   _anonymous70;
            即每次只能解開當前層的宏,所以__LINE__在第二層才能被解開;

            2、填充結構
            #define   FILL(a)    {a, #a}

            enum IDD{OPEN, CLOSE};
            typedef struct MSG{
               IDD id;
               const char * msg;
            }MSG;

            MSG _msg[] = {FILL(OPEN), FILL(CLOSE)};
            相當于:
            MSG _msg[] = {{OPEN, "OPEN"},
                           {CLOSE, "CLOSE"}};

            3、記錄文件名
            #define   _GET_FILE_NAME(f)    #f
            #define   GET_FILE_NAME(f)     _GET_FILE_NAME(f)
            static char   FILE_NAME[] = GET_FILE_NAME(__FILE__);

            4、得到一個數值類型所對應的字符串緩沖大小
            #define   _TYPE_BUF_SIZE(type)   sizeof #type
            #define   TYPE_BUF_SIZE(type)    _TYPE_BUF_SIZE(type)
            char   buf[TYPE_BUF_SIZE(INT_MAX)];
                  -->   char   buf[_TYPE_BUF_SIZE(0x7fffffff)];
                  -->   char   buf[sizeof "0x7fffffff"];
            這里相當于:
            char   buf[11];

            //////////////////////////////////////////////////////////////////////////////////////////////////////////////

            ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

            c和c++調式 利用宏獲得函數名
            僅僅為了獲取函數名,就在函數體中嵌入硬編碼的字符串,這種方法單調乏味還易導致錯誤,不如看一下怎樣使用新的C99特性,在程序運行時獲取函數名吧。
               對象反射庫、調試工具及代碼分析器,經常會需要在運行時訪問函數的名稱,直到不久前,唯一能完成此 項任務并且可移植的方法,是手工在函數體內嵌入一個帶有該函數名的硬編碼字符串,不必說,這種方法非常單調無奇,并且輕易導致錯誤。本文將要演示怎樣使用 新的C99特性,在運行時獲取函數名。
              那么怎樣以編程的方式從當前運行的函數中得到函數名呢?
              答案是:使用__FUNCTION__ 及相關宏。
              引出問題
              通常,在調試中最讓人心煩的階段,是不斷地檢查是否已調用了特定的函數。對此問題的解決方法,一般是添加一個cout或printf()——假如你使用C語言,如下所示:
            void myfunc()
            {
            cout<<"myfunc()"<<endl;
            //其他代碼
            }
            通常在一個典型的工程中,會包含有數千個函數,要在每個函數中都加入一條這樣的輸出語句,無疑難過上“蜀山”啊,因此,需要有一種機制,可以自動地完成這項操作。
              獲取函數名
              作為一個C++程序員,可能經常碰到 __TIME__、__FILE__、__DATE__ ,__LINE__ 這樣的宏,它們會在編譯時,分別轉換為包含編譯時間、處理的轉換單元名稱及當前時間的字符串。
               在最新的ISO C標準中,如大家所知的C99,加入了另一個有用的、類似宏的表達式__func__,其會報告未修飾過的(也就是未裁剪過的)、正在被訪問的函數名。請 注重,__func__不是一個宏,因為預處理器對此函數一無所知;相反,它是作為一個隱式聲明的常量字符數組實現的:
            static const char __func__[] = "function-name";
            在function-name處,為實際的函數名。為激活此特性,某些編譯器需要使用特定的編譯標志,請查看相應的編譯器文檔,以獲取具體的資料。
              有了它,我們可免去大多數通過手工修改,來顯示函數名的苦差事,以上的例子可如下所示進行重寫:
            void myfunc()
            {
            cout<<"__FUNCTION__"<<endl;
            }
            官 方C99標準為此目的定義的__func__標識符,確實值得大家關注,然而,ISO C++卻不完全支持所有的C99擴展,因此,大多數的編譯器提供商都使用 __FUNCTION__ 取而代之,而 __FUNCTION__ 通常是一個定義為 __func__ 的宏,之所以使用這個名字,是因為它已受到了大多數的廣泛支持。
              在Visual Studio 2005中,默認情況下,此特性是激活的,但不能與/EP和/P編譯選項同時使用。請注重在IDE環境中,不能識別__func__ ,而要用__FUNCTION__ 代替。
              Comeau的用戶也應使用 __FUNCTION__ ,而不是 __func__ 。
              C++ BuilderX的用戶則應使用稍稍不同的名字:__FUNC__ 。
              GCC 3.0及更高的版本同時支持 __func__ 和__FUNCTION__ 。
              一旦可自動獲取當前函數名,你可以定義一個如下所示顯示任何函數名的函數:
            void show_name(const char * name)
            {
            cout<<name<<endl;
            }
            void myfunc()
            {
            show_name(__FUNCTION__); //輸出:myfunc
            }
            void foo()
            {
            show_name(__FUNCTION__); //輸出:foo
            }
            因為 __FUNCTION__ 會在函數大括號開始之后就立即初始化,所以,foo()及myfunc()函數可在參數列表中安全地使用它,而不用擔心重載。
              簽名與修飾名
               __FUNCTION__ 特性最初是為C語言設計的,然而,C++程序員也會經常需要有關他們函數的額外信息,在Visual Studio 2005中,還支持另外兩種非標準的擴展特性:__FUNCDNAME__ 與 __FUNCSIG__ ,其分別轉譯為一個函數的修飾名與簽名。函數的修飾名非常有用,例如,在你想要檢查兩個編譯器是否共享同樣的ABI時,就可派得上用場,另外,它還能幫助 你破解那些含義模糊的鏈接錯誤,甚至還可用它從一個DLL中調用另一個用C++鏈接的函數。在下例中,show_name()報告了函數的修飾名:
            void myfunc()
            {
            show_name(__FUNCDNAME__); //輸出:?myfunc@@YAXXZ
            }
            一 個函數的簽名由函數名、參數列表、返回類型、內含的命名空間組成。假如它是一個成員函數,它的類名和const/volatile限定符也將是簽名的 一部分。以下的代碼演示了一個獨立的函數與一個const成員函數簽名間的不同之處,兩個函數的名稱、返回類型、參數完全相同:
            void myfunc()
            {
            show_name(__FUNCSIG__); // void __cdecl myfunc(void)
            }
            struct S
            {
            void myfunc() const
            {
            show_name(__FUNCSIG__); //void __thiscall S::myfunc(void) const
            }
            };



            posted on 2012-06-28 16:10 多彩人生 閱讀(369) 評論(0)  編輯 收藏 引用

            導航

            統計

            常用鏈接

            留言簿(3)

            隨筆分類

            隨筆檔案

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            手机看片久久高清国产日韩| 久久99国产乱子伦精品免费| 深夜久久AAAAA级毛片免费看| 中文字幕人妻色偷偷久久| 久久99精品国产自在现线小黄鸭| 国产精品久久久久久久午夜片 | 国产美女久久久| 久久综合给合综合久久| 精品久久久久久久久午夜福利| 久久精品国产WWW456C0M| 久久久久久亚洲精品成人| 国产精品成人99久久久久| 亚洲va国产va天堂va久久| 国产精品一区二区久久精品无码| 亚洲AV无码久久精品狠狠爱浪潮 | 久久综合视频网站| 9999国产精品欧美久久久久久| 97久久婷婷五月综合色d啪蜜芽| 国产精品美女久久久网AV| 精品熟女少妇av免费久久| 欧美日韩久久中文字幕| 久久久久国产日韩精品网站| 99久久99久久久精品齐齐| 久久无码高潮喷水| 欧美日韩成人精品久久久免费看| 久久国产高清字幕中文| 久久亚洲精品人成综合网| 久久久久亚洲AV成人网人人网站 | 久久久久免费精品国产| 久久亚洲欧美国产精品| 狠狠色丁香久久婷婷综合图片| 国产综合成人久久大片91| A级毛片无码久久精品免费| 久久99精品国产麻豆| 久久精品毛片免费观看| 嫩草伊人久久精品少妇AV| 欧美午夜精品久久久久免费视 | 五月丁香综合激情六月久久| 亚洲国产天堂久久综合| 香蕉久久AⅤ一区二区三区| 久久无码人妻精品一区二区三区|