• <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>

            唐吉訶德

              C++博客 :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
              5 Posts :: 75 Stories :: 3 Comments :: 0 Trackbacks

            常用鏈接

            留言簿(2)

            我參與的團(tuán)隊(duì)

            搜索

            •  

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            今天在網(wǎng)上突然發(fā)現(xiàn)了下面幾個(gè)關(guān)于c代碼中的宏定義的說明,回想下,好像在系統(tǒng)的代碼中也見過這些零散的定義,但沒有注意,看到別人總結(jié)了下,發(fā)現(xiàn)果然很有用,雖然不知有的道可用與否,但也不失為一種手段,所以就先把它摘抄下來,增加一點(diǎn)見識(shí):

            1,防止一個(gè)頭文件被重復(fù)包含
            #ifndef BODYDEF_H
            #define BODYDEF_H
              //頭文件內(nèi)容
            #endif
            2,得到指定地址上的一個(gè)字節(jié)或字
            #define  MEM_B( x )  ( *( (byte *) (x) ) )
            #define  MEM_W( x )  ( *( (word *) (x) ) )
            3,得到一個(gè)field在結(jié)構(gòu)體(struct)中的偏移量
            #define FPOS( type, field ) ( (dword) &(( type *) 0)-> field )
            4,得到一個(gè)結(jié)構(gòu)體中field所占用的字節(jié)數(shù)
            #define FSIZ( type, field ) sizeof( ((type *) 0)->field )
            5,得到一個(gè)變量的地址(word寬度)
            #define  B_PTR( var )  ( (byte *) (void *) &(var) )
            #define  W_PTR( var )  ( (word *) (void *) &(var) )
            6,將一個(gè)字母轉(zhuǎn)換為大寫
            #define  UPCASE( c ) ( ((c) >= ''a'' && (c) <= ''z'') ? ((c) - 0x20) : (c) )
            7,判斷字符是不是10進(jìn)值的數(shù)字
            #define  DECCHK( c ) ((c) >= ''0'' && (c) <= ''9'')
            8,判斷字符是不是16進(jìn)值的數(shù)字
            #define  HEXCHK( c ) ( ((c) >= ''0'' && (c) <= ''9'') ||((c) >= ''A'' && (c) <= ''F'') ||((c) >= ''a'' && (c) <= ''f'') )
            9,防止溢出的一個(gè)方法
            #define  INC_SAT( val )  (val = ((val)+1 > (val)) ? (val)+1 : (val))
            10,返回?cái)?shù)組元素的個(gè)數(shù)
            #define  ARR_SIZE( a )  ( sizeof( (a) ) / sizeof( (a[0]) ) )
            11,使用一些宏跟蹤調(diào)試
            ANSI標(biāo)準(zhǔn)說明了五個(gè)預(yù)定義的宏名。它們是:
            _LINE_ (兩個(gè)下劃線),對(duì)應(yīng)%d
            _FILE_     對(duì)應(yīng)%s
            _DATE_   對(duì)應(yīng)%s
            _TIME_    對(duì)應(yīng)%s
            _STDC_

             
            宏中"#"和"##"的用法
            我們使用#把宏參數(shù)變?yōu)橐粋€(gè)字符串,用##把兩個(gè)宏參數(shù)貼合在一起.
            #define STR(s)     #s
            #define CONS(a,b)  int(a##e##b)
            Printf(STR(vck));           // 輸出字符串"vck"
            printf("%d\n", CONS(2,3));  // 2e3 輸出:2000

            當(dāng)宏參數(shù)是另一個(gè)宏的時(shí)候
            需要注意的是凡宏定義里有用"#"或"##"的地方宏參數(shù)是不會(huì)再展開.
            #define A          (2)
            #define STR(s)     #s
            #define CONS(a,b)  int(a##e##b)
            printf("%s\n", CONS(A, A));               // compile error 
            這一行則是:
            printf("%s\n", int(AeA));
            INT_MAX和A都不會(huì)再被展開, 然而解決這個(gè)問題的方法很簡單. 加多一層中間轉(zhuǎn)換宏.
            加這層宏的用意是把所有宏的參數(shù)在這層里全部展開, 那么在轉(zhuǎn)換宏里的那一個(gè)宏(_STR)就能得到正確的宏參數(shù)
            #define STR(s)      _STR(s)          // 轉(zhuǎn)換宏
            #define CONS(a,b)   _CONS(a,b)       // 轉(zhuǎn)換宏
            printf("int max: %s\n", STR(INT_MAX));          // INT_MAX,int型的最大值,為一個(gè)變量 #include<climits>
            輸出為: int max: 0x7fffffff
            STR(INT_MAX) -->  _STR(0x7fffffff) 然后再轉(zhuǎn)換成字符串;

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

            "#"和"##"的一些應(yīng)用特例
            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表示該行行號(hào);
            第一層:ANONYMOUS(static int);  -->  __ANONYMOUS0(static int, __LINE__);
            第二層:                        -->  ___ANONYMOUS1(static int, _anonymous, 70);
            第三層:                        -->  static int  _anonymous70;
            即每次只能解開當(dāng)前層的宏,所以__LINE__在第二層才能被解開;

            2、填充結(jié)構(gòu)
            #define  FILL(a)   {a, #a}

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

            MSG _msg[] = {FILL(OPEN), FILL(CLOSE)};
            相當(dāng)于:
            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、得到一個(gè)數(shù)值類型所對(duì)應(yīng)的字符串緩沖大小
            #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"];
            這里相當(dāng)于:
            char  buf[11]; 

            C++提供的編譯預(yù)處理功能主要有以下三種:
              (一) 宏定義
              (二) 文件包含
              (三) 條件編譯

            在C++中,我們一般用const定義符號(hào)常量。很顯然,用const定義常量比用define定義常量更好。
              在使用宏定義時(shí)應(yīng)注意的是:
              (a) 在書寫#define 命令時(shí),注意<宏名>和<字符串>之間用空格分開,而不是用等號(hào)連接。
              (b) 使用#define定義的標(biāo)識(shí)符不是變量,它只用作宏替換,因此不占有內(nèi)存。
              (c) 習(xí)慣上用大寫字母表示<宏名>,這只是一種習(xí)慣的約定,其目的是為了與變量名區(qū)分,因?yàn)樽兞棵?br>                    通常用小寫字母。
              如果某一個(gè)標(biāo)識(shí)符被定義為宏名后,在取消該宏定義之前,不允許重新對(duì)它進(jìn)行宏定義。取消宏定義使用如下命令:
              #undef<標(biāo)識(shí)符>
              其中,undef是關(guān)鍵字。該命令的功能是取消對(duì)<標(biāo)識(shí)符>已有的宏定義。被取消了宏定義的標(biāo)識(shí)符,可以對(duì)它重新進(jìn)行定義。
              宏定義可以嵌套,已被定義的標(biāo)識(shí)符可以用來定義新的標(biāo)識(shí)符。例如:
              #define PI 3.14159265
              #define R 10
              #define AREA (PI*R*R)
            單的宏定義將一個(gè)標(biāo)識(shí)符定義為一個(gè)字符串,源程序中的該標(biāo)識(shí)符均以指定的字符串來代替。前面已經(jīng)說過,預(yù)處理命令不同于一般C++語句。因此預(yù)處理命令后通常不加分號(hào)。這并不是說所有的預(yù)處理命令后都不能有分號(hào)出現(xiàn)。由于宏定義只是用宏名對(duì)一個(gè)字符串進(jìn)行簡單的替換,因此如果在宏定義命令后加了分號(hào),將會(huì)連同分號(hào)一起進(jìn)行置換。

            帶參數(shù)的宏定義
              帶參數(shù)的宏定義的一般形式如下:
              #define <宏名>(<參數(shù)表>) <宏體>
              其中, <宏名>是一個(gè)標(biāo)識(shí)符,<參數(shù)表>中的參數(shù)可以是一個(gè),也可以是多個(gè),視具體情況而定,當(dāng)有多個(gè)參數(shù)的時(shí)候,每個(gè)參數(shù)之間用逗號(hào)分隔。<宏體>是被替換用的字符串,宏體中的字符串是由參數(shù)表中的各個(gè)參數(shù)組成的表達(dá)式。例如:
              #define SUB(a,b) a-b
            如果在程序中出現(xiàn)如下語句:
              result=SUB(2, 3)
            則被替換為:
              result=2-3;
            如果程序中出現(xiàn)如下語句:
              result= SUB(x+1, y+2);
            則被替換為:
              result=x+1-y+2;
              在這樣的宏替換過程中,其實(shí)只是將參數(shù)表中的參數(shù)代入到宏體的表達(dá)式中去,上述例子中,即是將表達(dá)式中的a和b分別用2和3代入。
              我們可以發(fā)現(xiàn):帶參的宏定義與函數(shù)類似。如果我們把宏定義時(shí)出現(xiàn)的參數(shù)視為形參,而在程序中引用宏定義時(shí)出現(xiàn)的參數(shù)視為實(shí)參。那么上例中的a和b就是形參,而2和3以及x+1和y+2都為實(shí)參。在宏替換時(shí),就是用實(shí)參來替換<宏體>中的形參。
            使用帶參數(shù)的宏定義時(shí)需要注意的是:
              (1)帶參數(shù)的宏定義的<宏體>應(yīng)寫在一行上,如果需要寫在多行上時(shí),在每行結(jié)束時(shí),使用續(xù)行符 "\"結(jié)
                              束,并在該符號(hào)后按下回車鍵,最后一行除外。
              (2)在書寫帶參數(shù)的宏定義時(shí),<宏名>與左括號(hào)之間不能出現(xiàn)空格,否則空格右邊的部分都作為宏體。
                              例如:
                        #define ADD (x,y) x+y
                              將會(huì)把"(x,y)x+y"的一個(gè)整體作為被定義的字符串。
             (3)定義帶參數(shù)的宏時(shí),宏體中與參數(shù)名相同的字符串適當(dāng)?shù)丶由蠄A括號(hào)是十分重要的,這樣能夠避免
                              可能產(chǎn)生的錯(cuò)誤。例如,對(duì)于宏定義:
                         #define SQ(x) x*x
                             當(dāng)程序中出現(xiàn)下列語句:
                        m=SQ(a+b);
                             替換結(jié)果為:
                       m=a+b*a+b;
            這可能不是我們期望的結(jié)果,如果需要下面的替換結(jié)果:
              m=(a+b)*(a+b);
            應(yīng)將宏定義修改為:
              #define SQ(x) (x)*(x)
              對(duì)于帶參的宏定義展開置換的方法是:在程序中如果有帶實(shí)參的宏(如"SUB(2,3)"),則按"#define"命令行中指定的字符串從左到右進(jìn)行置換。如果串中包含宏中的形參(如a、b),則將程序語句中相應(yīng)的實(shí)參(可以是常量、變量或者表達(dá)式)代替形參,如果宏定義中的字符串中的字符不是參數(shù)字符(如a-b中的-號(hào)),則保留。這樣就形成了置換的字符串。 C++提供的編譯預(yù)處理功能主要有以下三種:
              (一) 宏定義
              (二) 文件包含
              (三) 條件編譯

            在C++中,我們一般用const定義符號(hào)常量。很顯然,用const定義常量比用define定義常量更好。
              在使用宏定義時(shí)應(yīng)注意的是:
              (a) 在書寫#define 命令時(shí),注意<宏名>和<字符串>之間用空格分開,而不是用等號(hào)連接。
              (b) 使用#define定義的標(biāo)識(shí)符不是變量,它只用作宏替換,因此不占有內(nèi)存。
              (c) 習(xí)慣上用大寫字母表示<宏名>,這只是一種習(xí)慣的約定,其目的是為了與變量名區(qū)分,因?yàn)樽兞棵?br>                    通常用小寫字母。
              如果某一個(gè)標(biāo)識(shí)符被定義為宏名后,在取消該宏定義之前,不允許重新對(duì)它進(jìn)行宏定義。取消宏定義使用如下命令:
              #undef<標(biāo)識(shí)符>
              其中,undef是關(guān)鍵字。該命令的功能是取消對(duì)<標(biāo)識(shí)符>已有的宏定義。被取消了宏定義的標(biāo)識(shí)符,可以對(duì)它重新進(jìn)行定義。
              宏定義可以嵌套,已被定義的標(biāo)識(shí)符可以用來定義新的標(biāo)識(shí)符。例如:
              #define PI 3.14159265
              #define R 10
              #define AREA (PI*R*R)
            單的宏定義將一個(gè)標(biāo)識(shí)符定義為一個(gè)字符串,源程序中的該標(biāo)識(shí)符均以指定的字符串來代替。前面已經(jīng)說過,預(yù)處理命令不同于一般C++語句。因此預(yù)處理命令后通常不加分號(hào)。這并不是說所有的預(yù)處理命令后都不能有分號(hào)出現(xiàn)。由于宏定義只是用宏名對(duì)一個(gè)字符串進(jìn)行簡單的替換,因此如果在宏定義命令后加了分號(hào),將會(huì)連同分號(hào)一起進(jìn)行置換。

            帶參數(shù)的宏定義
              帶參數(shù)的宏定義的一般形式如下:
              #define <宏名>(<參數(shù)表>) <宏體>
              其中, <宏名>是一個(gè)標(biāo)識(shí)符,<參數(shù)表>中的參數(shù)可以是一個(gè),也可以是多個(gè),視具體情況而定,當(dāng)有多個(gè)參數(shù)的時(shí)候,每個(gè)參數(shù)之間用逗號(hào)分隔。<宏體>是被替換用的字符串,宏體中的字符串是由參數(shù)表中的各個(gè)參數(shù)組成的表達(dá)式。例如:
              #define SUB(a,b) a-b
            如果在程序中出現(xiàn)如下語句:
              result=SUB(2, 3)
            則被替換為:
              result=2-3;
            如果程序中出現(xiàn)如下語句:
              result= SUB(x+1, y+2);
            則被替換為:
              result=x+1-y+2;
              在這樣的宏替換過程中,其實(shí)只是將參數(shù)表中的參數(shù)代入到宏體的表達(dá)式中去,上述例子中,即是將表達(dá)式中的a和b分別用2和3代入。
              我們可以發(fā)現(xiàn):帶參的宏定義與函數(shù)類似。如果我們把宏定義時(shí)出現(xiàn)的參數(shù)視為形參,而在程序中引用宏定義時(shí)出現(xiàn)的參數(shù)視為實(shí)參。那么上例中的a和b就是形參,而2和3以及x+1和y+2都為實(shí)參。在宏替換時(shí),就是用實(shí)參來替換<宏體>中的形參。
            使用帶參數(shù)的宏定義時(shí)需要注意的是:
              (1)帶參數(shù)的宏定義的<宏體>應(yīng)寫在一行上,如果需要寫在多行上時(shí),在每行結(jié)束時(shí),使用續(xù)行符 "\"結(jié)
                              束,并在該符號(hào)后按下回車鍵,最后一行除外。
              (2)在書寫帶參數(shù)的宏定義時(shí),<宏名>與左括號(hào)之間不能出現(xiàn)空格,否則空格右邊的部分都作為宏體。
                              例如:
                        #define ADD (x,y) x+y
                              將會(huì)把"(x,y)x+y"的一個(gè)整體作為被定義的字符串。
             (3)定義帶參數(shù)的宏時(shí),宏體中與參數(shù)名相同的字符串適當(dāng)?shù)丶由蠄A括號(hào)是十分重要的,這樣能夠避免
                              可能產(chǎn)生的錯(cuò)誤。例如,對(duì)于宏定義:
                         #define SQ(x) x*x
                             當(dāng)程序中出現(xiàn)下列語句:
                        m=SQ(a+b);
                             替換結(jié)果為:
                       m=a+b*a+b;
            這可能不是我們期望的結(jié)果,如果需要下面的替換結(jié)果:
              m=(a+b)*(a+b);
            應(yīng)將宏定義修改為:
              #define SQ(x) (x)*(x)
              對(duì)于帶參的宏定義展開置換的方法是:在程序中如果有帶實(shí)參的宏(如"SUB(2,3)"),則按"#define"命令行中指定的字符串從左到右進(jìn)行置換。如果串中包含宏中的形參(如a、b),則將程序語句中相應(yīng)的實(shí)參(可以是常量、變量或者表達(dá)式)代替形參,如果宏定義中的字符串中的字符不是參數(shù)字符(如a-b中的-號(hào)),則保留。這樣就形成了置換的字符串。

            解剖MFC自動(dòng)生成的宏定義

            一、關(guān)于DECLARE_MESSAGE_MAP宏定義
            使用MFC向?qū)В贏pplicationType頁面選擇DialogBased,生成一個(gè)對(duì)話框項(xiàng)目,Dialog類命名為CCapturePacketDlg,在CCapturePacketDlg.cpp中自動(dòng)產(chǎn)生下列代碼:

            1 BEGIN_MESSAGE_MAP(CCapturePacketDlg, CDialog)
            2     ON_WM_PAINT()
            3 END_MESSAGE_MAP()
            1. 先來分析ON_WM_PAINT(),在頭文件“afxmsg.h”有它的宏定義,如下:
            1 #define  ON_WM_PAINT() \
            2      { WM_PAINT,  0 0 0 , AfxSig_vv, \
            3         (AFX_PMSG)(AFX_PMSGW) \
            4         (static_cast <   void  (AFX_MSG_CALL CWnd:: * )( void >  (  & ThisClass :: OnPaint)) }
            ,
            說明:層次序號(hào)x.y.z表示x為根節(jié)點(diǎn)也就是上面代碼中的行號(hào),y、z為上一級(jí)的定義展開。
            2.1 #define WM_PAINT                        0x000F
            2.2 AfxSig_vv = AfxSig_v_v_v
            2.2.1 enum AfxSig::AfxSig_v_v_v = 19

            3.1 AFX_PMSG:typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void); //為一個(gè)函數(shù)指針
            3.2 AFX_PMSGW:typedef void (AFX_MSG_CALL CWnd::*AFX_PMSGW)(void);   //為一個(gè)函數(shù)指針

            將ON_WM_PAINT()完全展開:
            1{
            2        0x000F
            3        0,
            4        0,
            5        0,
            6        19,
            7        //Converts OnPaint to the type of CCmdTarget finally. Derive Class 's pointer -> Base Class's pointer
            8        (AFX_MSG_CALL CCmdTarget::*)((AFX_MSG_CALL CWnd::*)(static_cast< void (AFX_MSG_CALL CWnd::*)(void>(&ThisClass :: OnPaint))
            9    }

               2.   再來分析BEGIN_MESSAGE_MAP(CCapturePacketDlg, CDialog),在“afxwin.h”中有定義:

             1#define BEGIN_MESSAGE_MAP(theClass, baseClass) \
             2    PTM_WARNING_DISABLE \
             3    const AFX_MSGMAP* theClass::GetMessageMap() const \
             4        return GetThisMessageMap(); } \
             5    const AFX_MSGMAP* PASCAL theClass::GetThisMessageMap() \
             6    { \
             7        typedef theClass ThisClass;                           \
             8        typedef baseClass TheBaseClass;                       \
             9        static const AFX_MSGMAP_ENTRY _messageEntries[] =  \
            10        {

            2.1 PTM_WARNING_DISABLE:
            #define PTM_WARNING_DISABLE \
             __pragma(warning( push ))  \ //#pragma warning( push [ ,n ] ),Where n represents a warning level (1 through 4).
                                                          //The pragma warning( push ) stores the current warning state for all warnings.
             __pragma(warning( disable : 4867 ))//Do not issue the specified warning message(s).
            //http://msdn2.microsoft.com/en-us/2c8f766e.aspx
            // Allows selective modification of the behavior of compiler warning messages.
            3.1 struct AFX_MSGMAP
             {
              3.1.1 const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
              3.1.2 const AFX_MSGMAP_ENTRY* lpEntries;
             };
            3.1.2 struct AFX_MSGMAP_ENTRY
             {
              UINT nMessage;   // windows message
              UINT nCode;      // control code or WM_NOTIFY code
              UINT nID;        // control ID (or 0 for windows messages)
              UINT nLastID;    // used for entries specifying a range of control id's
              UINT_PTR nSig;       // signature type (action) or pointer to message #
              3.1.2.1 AFX_PMSG pfn;    // routine to call (or special value)
             };
             3.1.2.1 typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);

            5.1 #define PASCAL      __stdcall
            將BEGIN_MESSAGE_MAP(CCapturePacketDlg, CDialog)完全展開:

             1__pragma(warning( push )) __pragma(warning( disable : 4867 ))
             2    const struct AFX_MSGMAP* CCapturePacketDlg::GetMessageMap() const
             3    
             4        return GetThisMessageMap(); 
             5    }

             6    const struct AFX_MSGMAP* __stdcall CCapturePacketDlg::GetThisMessageMap()
             7    {
             8        typedef CCapturePacketDlg ThisClass;                           
             9        typedef CDialog TheBaseClass;        
            10        static const struct AFX_MSGMAP_ENTRY _messageEntries[] = 
            11        {

               3    最后分析END_MESSAGE_MAP(),在“afxwin.h”中有定義:

            1#define END_MESSAGE_MAP() \
            2        {0000, AfxSig_end, (AFX_PMSG)0 } \
            3    }; \
            4        static const AFX_MSGMAP messageMap = \
            5        &TheBaseClass::GetThisMessageMap, &_messageEntries[0] }; \
            6        return &messageMap; \
            7    }                                  \
            8    PTM_WARNING_RESTORE

            2.1 AfxSig_end:enum AfxSig.AfxSig_end = 0
            2.2 AFX_PMSG:typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);//函數(shù)指針

            4.1 struct AFX_MSGMAP
             {
              const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
              const AFX_MSGMAP_ENTRY* lpEntries;
             };

            8.1 #define PTM_WARNING_RESTORE \
             __pragma(warning( pop ))
            //pop restores the state of all warnings (including 4705, 4706, and 4707) to what it was at the beginning of the code.

            ·最后將

            1BEGIN_MESSAGE_MAP(CCapturePacketDlg, CDialog)
            2    ON_WM_PAINT()
            3END_MESSAGE_MAP()
            完全展開為:
             1__pragma(warning( push )) __pragma(warning( disable : 4867 ))
             2    const struct AFX_MSGMAP* CCapturePacketDlg::GetMessageMap() const
             3    
             4        return GetThisMessageMap(); 
             5    }

             6    const struct AFX_MSGMAP* __stdcall CCapturePacketDlg::GetThisMessageMap()
             7    {
             8        typedef CCapturePacketDlg ThisClass;                           
             9        typedef CDialog TheBaseClass;        
            10        static const struct AFX_MSGMAP_ENTRY _messageEntries[] = 
            11        {
            12            {
            13                0x000F
            14                0,
            15                0,
            16                0,
            17                19,
            18                //Converts OnPaint to the type of CCmdTarget finally. Derive Class 's pointer -> Base Class's pointer
            19                (AFX_MSG_CALL CCmdTarget::*)((AFX_MSG_CALL CWnd::*)(static_cast< void (AFX_MSG_CALL CWnd::*)(void>(&ThisClass :: OnPaint))
            20            }
            ,
            21            //add others
            22            {
            23                0,
            24                0,
            25                0,
            26                0,
            27                0,
            28                (AFX_PMSG)0
            29            }

            30        }

            31        static const struct AFX_MSGMAP messageMap = 
            32        {
            33            &TheBaseClass::GetThisMessageMap,
            34            &_messageEntries[0]
            35        }
            ;
            36        return &messageMap;
            37    }

            38__pragma(warning( pop ))
            39
            其中GetMessageMap()是在哪里聲明的呢?在CCapturePacketDlg的定義中有一個(gè)這樣的宏:DECLARE_MESSAGE_MAP()
            老辦法查看它的定義:
            1#define DECLARE_MESSAGE_MAP() \
            2protected: \
            3    static const AFX_MSGMAP* PASCAL GetThisMessageMap(); \
            4    virtual const AFX_MSGMAP* GetMessageMap() const; \
            注意函數(shù)為static,即它們是類的函數(shù)。函數(shù)中的static變量實(shí)際也在類對(duì)象未生成之前已經(jīng)存在。(這種說法不知道是否正確?)
            小結(jié):
            每次用MFC類向?qū)梢粋€(gè)類時(shí),系統(tǒng)會(huì)在類的聲明部分添加兩個(gè)方法的聲明:GetThisMessageMap(),GetMessageMap()。在類的實(shí)現(xiàn)部分.cpp文件中加上這兩個(gè)方法的定義。
            當(dāng)然這所有的代碼都是由系統(tǒng)生成的,如果我們要定義自己的消息處理函數(shù)呢,例如,我們要添加一個(gè)按鈕(ID為:IDC_BUTTON1)的單擊處理函數(shù)我們可以添加宏ON_NOTIFY(NM_CLICK, IDC_BUTTON1, OnMyClick),OnMyClick為自定義函數(shù),但是他必須與ON_NOTIFY中的函數(shù)原型一致。

            二、關(guān)于DECLARE_DYNCREATE宏
            使用MFC向?qū)В贏pplicationType頁面選擇SingleDocument,生成一個(gè)單文檔項(xiàng)目,Document類命名為CDynamicDoc,在CDynamicDoc.h中自動(dòng)產(chǎn)生DECLARE_DYNCREATE(CDynamicDoc),CDynamicDoc.cpp中產(chǎn)生IMPLEMENT_DYNCREATE(CDynamicDoc, CDocument)。
            1、展開CDynamicDoc.h中的DECLARE_DYNCREATE(CDynamicDoc):
            1// not serializable, but dynamically constructable
            2    #define DECLARE_DYNCREATE(class_name) \
            3        DECLARE_DYNAMIC(class_name) \
            4        static CObject* PASCAL CreateObject();
            3.1如下定義:
            1#ifdef _AFXDLL
            2    #define DECLARE_DYNAMIC(class_name) \
            3    protected: \
            4        static CRuntimeClass* PASCAL _GetBaseClass(); \
            5    public: \
            6        static const CRuntimeClass class##class_name; \
            7        static CRuntimeClass* PASCAL GetThisClass(); \
            8        virtual CRuntimeClass* GetRuntimeClass() const; \
            so the result(DECLARE_DYNCREATE(CDynamicDoc)) of combining the above two is following:
            1protected
            2        static CRuntimeClass* PASCAL _GetBaseClass(); 
            3    public
            4        static const CRuntimeClass classCDynamicDoc; 
            5        static CRuntimeClass* PASCAL GetThisClass(); 
            6        virtual CRuntimeClass* GetRuntimeClass() const
            7        static CObject* PASCAL CreateObject();

            2、展開CDynamicDoc.cpp中的IMPLEMENT_DYNCREATE(CDynamicDoc, CDocument):
            1#define IMPLEMENT_DYNCREATE(class_name, base_class_name) \
            2    CObject* PASCAL class_name::CreateObject() \
            3        return new class_name; } \
            4    IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, \
            5        class_name::CreateObject, NULL)
            4.1如下定義:
             1#define IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew, class_init) \
             2    CRuntimeClass* PASCAL class_name::_GetBaseClass() \
             3        return RUNTIME_CLASS(base_class_name); } \
             4    AFX_COMDAT const CRuntimeClass class_name::class##class_name = { \
             5        #class_name, sizeof(class class_name), wSchema, pfnNew, \
             6            &class_name::_GetBaseClass, NULL, class_init }
            ; \
             7    CRuntimeClass* PASCAL class_name::GetThisClass() \
             8        return _RUNTIME_CLASS(class_name); } \
             9    CRuntimeClass* class_name::GetRuntimeClass() const \
            10        return _RUNTIME_CLASS(class_name); } \
            4.1.2 CRuntimeClass如下定義:
             1struct CRuntimeClass
             2    {
             3    // Attributes
             4        LPCSTR m_lpszClassName;
             5        int m_nObjectSize;
             6        UINT m_wSchema; // schema number of the loaded class
             7        CObject* (PASCAL* m_pfnCreateObject)(); // NULL => abstract class
             8    #ifdef _AFXDLL
             9        CRuntimeClass* (PASCAL* m_pfnGetBaseClass)();
            10    #else
            11        CRuntimeClass* m_pBaseClass;
            12    #endif
            13
            14    // Operations
            15        CObject* CreateObject();
            16        BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const;
            17
            18        // dynamic name lookup and creation
            19        static CRuntimeClass* PASCAL FromName(LPCSTR lpszClassName);
            20        static CRuntimeClass* PASCAL FromName(LPCWSTR lpszClassName);
            21        static CObject* PASCAL CreateObject(LPCSTR lpszClassName);
            22        static CObject* PASCAL CreateObject(LPCWSTR lpszClassName);
            23
            24    // Implementation
            25        void Store(CArchive& ar) const;
            26        static CRuntimeClass* PASCAL Load(CArchive& ar, UINT* pwSchemaNum);
            27
            28        // CRuntimeClass objects linked together in simple list
            29        CRuntimeClass* m_pNextClass;       // linked list of registered classes
            30        const AFX_CLASSINIT* m_pClassInit;
            31    }
            ;
            4.1.2.30 AFX_CLASSINIT如下定義:(這個(gè)變量非常重要,它完成了將新的類加在List頭部的功能,List中的節(jié)點(diǎn)類型就是CRuntimeClass)
             1/////////////////////////////////////////////////////////////////////////////
             2    // Basic object model
             3
             4    // generate static object constructor for class registration
             5    void AFXAPI AfxClassInit(CRuntimeClass* pNewClass);
             6    struct AFX_CLASSINIT
             7        { AFX_CLASSINIT(CRuntimeClass* pNewClass) { AfxClassInit(pNewClass); } };
             8    //C:\Program Files\Microsoft Visual Studio 8\VC\atlmfc\src\mfc\objcore.cpp Line157
             9    void AFXAPI AfxClassInit(CRuntimeClass* pNewClass)
            10    {
            11        AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
            12        AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
            13        pModuleState->m_classList.AddHead(pNewClass);
            14        AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
            15    }

            16    //可以將AfxClassInit()函數(shù)的功能簡單的如下表示:
            17    AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass* pNewClass)
            18    {
            19        pNewClass->m_pNextClass = CRuntimeClass::pFirstClass;
            20        CRuntimeClass::pFirstClass = pNewClass;
            21    }

            4.1.3 RUNTIME_CLASS如下定義:
            1#define RUNTIME_CLASS(class_name) (class_name::GetThisClass())
            4.1.4 AFX_COMDAT如下定義:
            1#define AFX_COMDAT __declspec(selectany)
            說明:“#”——operator (#) converts macro parameters to string literals without expanding the parameter definition.
            “##”——operator (##), which is sometimes called the "merging" operator, is used in both object-like and function-like macros.
            4.1.8 _RUNTIME_CLASS如下定義:
            1#define _RUNTIME_CLASS(class_name) ((CRuntimeClass*)(&class_name::class##class_name))
            so the result(IMPLEMENT_DYNCREATE(CDynamicDoc, CDocument)) of combining the aboves is following:
             1//CDynamicDoc, CDocument->class_name, base_class_name
             2  static  CObject* PASCAL CDynamicDoc::CreateObject()
             
            3    
             
            4        return new CDynamicDoc; 
             
            5    }

             
            6
             
            7    static CRuntimeClass* PASCAL CDynamicDoc::_GetBaseClass()
             
            8    
             
            9        return CDocument::GetThisClass()
            10    }

            11
            12    __declspec(selectany) static const CRuntimeClass CDynamicDoc::classCDynamicDoc = 
            13    {
            14        "CDynamicDoc"
            15        , sizeof(class CDynamicDoc)
            16        , 0xFFFF
            17        , CDynamicDoc::CreateObject
            18        , &CDynamicDoc::_GetBaseClass
            19        , NULL
            20        , NULL
            21    }
            ;
            22
            23    static CRuntimeClass* PASCAL CDynamicDoc::GetThisClass()
            24    {
            25        return ((CRuntimeClass*)(&CDynamicDoc::classCDynamicDoc));
            26    }

            27
            28    CRuntimeClass* CDynamicDoc::GetRuntimeClass() const
            29    {
            30        return ((CRuntimeClass*)(&CDynamicDoc::classCDynamicDoc));
            31    }
            小結(jié):注意了,上面的成員變量、很多函數(shù)都是static
            如果你想看這些宏的簡化版,可以參考侯老的《深入淺出MFC》,如下:

             1//in header file
             2class CView : public CWnd
             3{
             4public:
             5    static CRuntimeClass classCView;
             6    virtual CRuntimeClass* GetRuntimeClass() const;
             7    //……
             8}
            ;
             9//in implementation file
            10static char_lpszCView = "CView";
            11CRuntimeClass CView::classCView =
            12{
            13    _lpszCView
            14    , sizeof(CView)
            15    , 0xFFF
            16    , NULL
            17    , &CWnd::classCWnd
            18    , NULL
            19}
            ;
            20static AFX_CLASSINIT _init_CView(&CView::classCView)
            21{
            22    (&CView::classCView)->m_pNextClass = CRuntimeClass::pFirstClass;
            23    CRuntimeClass::pFirstClass = &CView::classCView;
            24}

            25CRuntimeClass* CView::GetRuntimeClass() const
            26{
            27    return &CView::classCView;
            28}
            其中他將CRuntimeClass簡化定義為:
            struct CRuntimeClass
            {
            // Attributes
                    LPCSTR m_lpszClassName;
                    int m_nObjectSize;
                    UINT m_wSchema; // schema number of the loaded class
                    CObject* (PASCAL* m_pfnCreateObject)(); // NULL => abstract class
                    CRuntimeClass* m_pBaseClass;

                    // CRuntimeClass objects linked together in simple list
                    static CRuntimeClass* pFirstClass; // start of class list
                    CRuntimeClass* m_pNextClass;       // linked list of registered classes
            };

            三、宏DECLARE_SERIAL(CStroke)、IMPLEMENT_SERIAL(CStroke, CObject, 1),給出它們的宏定義及結(jié)果:
             1//declaration file
             2#define DECLARE_SERIAL(class_name) \
             3    _DECLARE_DYNCREATE(class_name) \
             4    AFX_API friend CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb);
             5
             6    #define _DECLARE_DYNCREATE(class_name) \
             7    _DECLARE_DYNAMIC(class_name) \
             8    static CObject* PASCAL CreateObject();
             9
            10    #define _DECLARE_DYNAMIC(class_name) \
            11    protected: \
            12        static CRuntimeClass* PASCAL _GetBaseClass(); \
            13    public: \
            14        static CRuntimeClass class##class_name; \
            15        static CRuntimeClass* PASCAL GetThisClass(); \
            16        virtual CRuntimeClass* GetRuntimeClass() const; \
            17//implement file
            18#define IMPLEMENT_SERIAL(class_name, base_class_name, wSchema) \
            19    CObject* PASCAL class_name::CreateObject() \
            20        return new class_name; } \
            21    extern AFX_CLASSINIT _init_##class_name; \
            22    _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, \
            23        class_name::CreateObject, &_init_##class_name) \
            24    AFX_CLASSINIT _init_##class_name(RUNTIME_CLASS(class_name)); \
            25    CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb) \
            26        { pOb = (class_name*) ar.ReadObject(RUNTIME_CLASS(class_name)); \
            27            return ar; }
             \
            28    
            29    // generate static object constructor for class registration
            30    void AFXAPI AfxClassInit(CRuntimeClass* pNewClass);
            31    struct AFX_CLASSINIT
            32        { AFX_CLASSINIT(CRuntimeClass* pNewClass) { AfxClassInit(pNewClass); } };
            33
            34    void AFXAPI AfxClassInit(CRuntimeClass* pNewClass)
            35    {
            36        AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
            37        AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
            38        pModuleState->m_classList.AddHead(pNewClass);
            39        AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
            40    }

            41
            42    
            43    #define _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew, class_init) \
            44    CRuntimeClass* PASCAL class_name::_GetBaseClass() \
            45        return RUNTIME_CLASS(base_class_name); } \
            46    AFX_COMDAT CRuntimeClass class_name::class##class_name = { \
            47        #class_name, sizeof(class class_name), wSchema, pfnNew, \
            48            &class_name::_GetBaseClass, NULL, class_init }
            ; \
            49    CRuntimeClass* PASCAL class_name::GetThisClass() \
            50        return _RUNTIME_CLASS(class_name); } \
            51    CRuntimeClass* class_name::GetRuntimeClass() const \
            52        return _RUNTIME_CLASS(class_name); } \
            53    
            54    #define _RUNTIME_CLASS(class_name) ((CRuntimeClass*)(&class_name::class##class_name))
            55
            56    #define RUNTIME_CLASS(class_name) (class_name::GetThisClass())

             1//header file
             2    protected
             3        static CRuntimeClass* PASCAL _GetBaseClass(); 
             4    public
             5        static CRuntimeClass classCStroke; 
             6        static CRuntimeClass* PASCAL GetThisClass(); 
             7        virtual CRuntimeClass* GetRuntimeClass() const
             8        static CObject* PASCAL CreateObject();
             9        AFX_API friend CArchive& AFXAPI operator>>(CArchive& ar, CStroke* &pOb);
            10//implement file
            11    //static
            12    static CObject* PASCAL CStroke::CreateObject()
            13    {
            14        return new CStroke;
            15    }

            16    //static
            17    static CRuntimeClass* PASCAL CStroke::GetThisClass();
            18    
            19        return ((CRuntimeClass*)(&CStroke::classCStroke))
            20    }

            21    //static
            22    static CRuntimeClass* PASCAL CStroke::_GetBaseClass() 
            23    
            24        return (CObject::GetThisClass());
            25    }

            26    //static
            27    static AFX_COMDAT CRuntimeClass CStroke::classCStroke = 
            28    {
            29        "CStroke"
            30        , sizeof(class CStroke)
            31        , 1
            32        , CStroke::CreateObject
            33        , &class_name::_GetBaseClass
            34        , NULL
            35        , &_init_CStroke 
            36    }

            37    CRuntimeClass* CStroke::GetRuntimeClass() const
            38    
            39        return ((CRuntimeClass*)(&CStroke::classCStroke)); 
            40    }

            41    extern struct AFX_CLASSINIT _init_CStroke;
            42    struct AFX_CLASSINIT _init_CStroke
            43    {
            44        void AFXAPI AfxClassInit(CRuntimeClass* CStroke)
            45        {
            46            AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
            47            AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
            48            pModuleState->m_classList.AddHead(CStroke);
            49            AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
            50        }

            51    }
            ;
            52    CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb) 
            53    
            54        pOb = (CStroke*) ar.ReadObject(RUNTIME_CLASS(CStroke));
            55        return ar; 
            56    }
            總結(jié),一旦RUNTIME_CLASS(CStroke)由#define RUNTIME_CLASS(class_name) (class_name::GetThisClass())也就是CStroke::GetThisClass() 即
            CStroke::classCStroke =
             {
              "CStroke"
              , sizeof(class CStroke)
              , 1
              , CStroke::CreateObject
              , &class_name::_GetBaseClass
              , NULL
              , &_init_CStroke
             }
            其中,由extern AFX_CLASSINIT _initCStroke可知_init_CStroke是一個(gè)結(jié)構(gòu)體AFX_CLASSINIT的對(duì)象,此結(jié)構(gòu)體有構(gòu)造函數(shù):
             1void AFXAPI AfxClassInit(CRuntimeClass* pNewClass);
             2    struct AFX_CLASSINIT
             3        { AFX_CLASSINIT(CRuntimeClass* pNewClass) { AfxClassInit(pNewClass); } };
             4
             5    void AFXAPI AfxClassInit(CRuntimeClass* pNewClass)
             6    {
             7        AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
             8        AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
             9        pModuleState->m_classList.AddHead(pNewClass);
            10        AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
            11    }
            所以一旦返回classCStroke,也就調(diào)用了_init_CStroke的構(gòu)造函數(shù)即將類CStroke添加到了全局變量m_classList類的List中了,同時(shí)在變量classCStroke中,也可以得到類CStroke的名稱、大小、一個(gè)CStroke的對(duì)象、類CStroke的基類以及AFX_CLASSINIT結(jié)構(gòu)的一個(gè)對(duì)象。
            posted on 2010-10-26 12:00 心羽 閱讀(1565) 評(píng)論(0)  編輯 收藏 引用 所屬分類: 需求分析
            国产亚洲综合久久系列| 久久久久久亚洲精品不卡| 欧美成a人片免费看久久| 亚洲色大成网站WWW久久九九| 久久99热这里只频精品6| 亚洲国产另类久久久精品黑人| 久久婷婷五月综合97色一本一本| 久久99国产精品一区二区| 国产精品免费久久久久影院| 亚洲国产成人精品女人久久久| 精品午夜久久福利大片| 丰满少妇人妻久久久久久4| 人妻无码精品久久亚瑟影视 | 无码人妻少妇久久中文字幕蜜桃| 亚洲国产美女精品久久久久∴| 99久久国产热无码精品免费久久久久| 久久精品无码一区二区WWW| 久久精品成人影院| 欧美噜噜久久久XXX| 久久久久香蕉视频| 久久精品国产99国产电影网 | 一本久久a久久精品亚洲| 久久精品国产影库免费看| 国产成人无码精品久久久性色| 日本免费久久久久久久网站| 久久不见久久见免费视频7| 久久夜色精品国产欧美乱| 午夜精品久久久久久影视777| 国产精品久久久久…| 亚洲国产精品久久久久| 伊人久久久AV老熟妇色| 久久精品国产欧美日韩99热| 伊人久久亚洲综合影院| 久久99精品久久久久久水蜜桃| 久久激情亚洲精品无码?V| 精品久久久久久久久中文字幕| 久久综合久久自在自线精品自| 亚洲第一极品精品无码久久| 香蕉久久av一区二区三区| 无码精品久久久天天影视| 欧美牲交A欧牲交aⅴ久久 |