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

            平凡的天才

            目的是為人類造福
            posts - 20, comments - 41, trackbacks - 0, articles - 6
              C++博客 :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

            轉(zhuǎn)自http://blog.csdn.net/fornormandy/archive/2004/08/19/79512.aspx
            按照c++標(biāo)準(zhǔn),編譯器會(huì)生成五個(gè)默認(rèn)成員函數(shù):
            默認(rèn)構(gòu)造函數(shù)
            拷貝構(gòu)造函數(shù)
            析構(gòu)函數(shù)
            operator=
            operator&


            class A
            {
            public:
            A(int i) : m_i(i){}
            int m_i;
            };

            分別說(shuō)說(shuō)吧:
            1. A a = 0;
            首先, compiler認(rèn)為這樣寫是不符合規(guī)矩的, 因?yàn)锳 = A才是正常行為。
            但是她并不放棄, 通過(guò)搜索, 發(fā)現(xiàn)A可以根據(jù)一個(gè)int構(gòu)造, 同時(shí)這個(gè)A(int i)沒(méi)有用explicit修飾過(guò)。
            那么A a = 0; 這樣的一句話隨即轉(zhuǎn)變成:
            A tmp(0);
            A a = tmp;
            需要說(shuō)明的是, A a = tmp是調(diào)用的copy ctor, 雖然class A中并沒(méi)有, 但是通常不寫copy ctor的話,
            compiler都會(huì)生成一個(gè)memberwise assignment操作性質(zhì)的ctor, 底層實(shí)現(xiàn)通常會(huì)以memcpy進(jìn)行。

            2. a = 10;
            首先, 這樣同ctor的情況一樣, compiler無(wú)法直接進(jìn)行操作。
            類推, 等同于代碼:
            A tmp(10);
            a = tmp;
            需要注意的是, a = tmp是調(diào)用的assignment操作, 同ctor一樣,我們自己不寫, 編譯器同樣進(jìn)行
            memberwise assignment操作。

            3. fn(A a)
            同樣, fn(10)也是不對(duì)的, 但是"按照慣例", 呵呵, 會(huì)有:
            A tmp(10);
            fn(tmp);

            另外, 為你解惑:
            copy ctor的寫法只能是T::T(const T &);
            而assignment的寫法可以多變, 即任意. 以T為例,
            可以有
            T &operator = (int n);
            也可有
            T &operator = (const char *);
            當(dāng)然, 你要確認(rèn)如此的定義是對(duì)T而言有意義.

            然后, 上述a = tmp, 即調(diào)用的默認(rèn)的、標(biāo)準(zhǔn)的、自動(dòng)生成的T &operator = (const T &).
            開(kāi)銷是會(huì)有一個(gè)臨時(shí)的A tmp生成, 然后memcpy.
            但如果你自已寫了T &operator = (int n), 那么a = 10即意味著a.m_i = 10.
            當(dāng)然, 以開(kāi)銷而言要視你的T &operator = (int n)是否為inline了.

            對(duì)于explicit, 當(dāng)修飾explicit A(int i) : m_i(i){}, 那么即告訴compiler不要在私底下做那么多的轉(zhuǎn)換動(dòng)作.
            而且自動(dòng)生成如A tmp(0)這樣的東西是我們不想要的, 因?yàn)槟承┣闆r下自動(dòng)轉(zhuǎn)換這種行為是錯(cuò)誤的.

            最后, 相關(guān)此類問(wèn)題, 還有一個(gè)話題, 即class A可以有operator int(), 會(huì)在
            fn(int n){}
            A a(3);
            fn(a)
            起到魔術(shù)般的作用. 關(guān)于這個(gè), 留給你自己看看書(shū)吧:)

            最后,祝學(xué)習(xí)C++的路上一帆風(fēng)順。Good luck~

            posted @ 2007-03-04 11:32 平凡的天才 閱讀(4789) | 評(píng)論 (1)編輯 收藏

            原文鏈接:What static_cast<> is actually doing

            本文討論static_cast<> 和 reinterpret_cast<>。

            介紹
            大多程序員在學(xué)C++前都學(xué)過(guò)C,并且習(xí)慣于C風(fēng)格(類型)轉(zhuǎn)換。當(dāng)寫C++(程序)時(shí),有時(shí)候我們?cè)谑褂胹tatic_cast<>和reinterpret_cast<>時(shí)可能會(huì)有點(diǎn)模糊。在本文中,我將說(shuō)明static_cast<>實(shí)際上做了什么,并且指出一些將會(huì)導(dǎo)致錯(cuò)誤的情況。

            泛型(Generic Types)

                    float f = 12.3;
            float* pf = &f;

            // static cast
            // 成功編譯, n = 12
            int n = static_cast(f);
            // 錯(cuò)誤,指向的類型是無(wú)關(guān)的(譯注:即指針變量pf是float類型,現(xiàn)在要被轉(zhuǎn)換為int類型) //int* pn = static_cast(pf);
            //成功編譯
            void* pv = static_cast(pf);
            //成功編譯, 但是 *pn2是無(wú)意義的內(nèi)存(rubbish)
            int* pn2 = static_cast(pv);

            // reinterpret_cast
            //錯(cuò)誤,編譯器知道你應(yīng)該調(diào)用static_cast
            //int i = reinterpret_cast(f);
            //成功編譯, 但是 *pn 實(shí)際上是無(wú)意義的內(nèi)存,和 *pn2一樣
            int* pi = reinterpret_cast(pf);

            簡(jiǎn)而言之,static_cast<> 將嘗試轉(zhuǎn)換,舉例來(lái)說(shuō),如float-到-integer,而reinterpret_cast<>簡(jiǎn)單改變編譯器的意圖重新考慮那個(gè)對(duì)象作為另一類型。

            指針類型(Pointer Types)

            指針轉(zhuǎn)換有點(diǎn)復(fù)雜,我們將在本文的剩余部分使用下面的類:
            class CBaseX
            {
            public:
            int x;
            CBaseX() { x = 10; }
            void foo() { printf("CBaseX::foo() x=%d\n", x); }
            };

            class CBaseY
            {
            public:
            int y;
            int* py;
            CBaseY() { y = 20; py = &y; }
            void bar() { printf("CBaseY::bar() y=%d, *py=%d\n", y, *py); }
            };

            class CDerived : public CBaseX, public CBaseY
            {
            public:
            int z;
            };

            情況1:兩個(gè)無(wú)關(guān)的類之間的轉(zhuǎn)換



                  // Convert between CBaseX* and CBaseY*
            // CBaseX* 和 CBaseY*之間的轉(zhuǎn)換
            CBaseX* pX = new CBaseX();
            // Error, types pointed to are unrelated
            // 錯(cuò)誤, 類型指向是無(wú)關(guān)的
            // CBaseY* pY1 = static_cast(pX);
            // Compile OK, but pY2 is not CBaseX
            // 成功編譯, 但是 pY2 不是CBaseX
            CBaseY* pY2 = reinterpret_cast(pX);
            // System crash!!
            // 系統(tǒng)崩潰!!
            // pY2->bar();
            正如我們?cè)诜盒屠又兴J(rèn)識(shí)到的,如果你嘗試轉(zhuǎn)換一個(gè)對(duì)象到另一個(gè)無(wú)關(guān)的類static_cast<>將失敗,而reinterpret_cast<>就總是成功“欺騙”編譯器:那個(gè)對(duì)象就是那個(gè)無(wú)關(guān)類。

            情況2:轉(zhuǎn)換到相關(guān)的類
                  1. CDerived* pD = new CDerived();
            2. printf("CDerived* pD = %x\n", (int)pD);
            3.
            4. // static_cast CDerived* -> CBaseY* -> CDerived*
            //成功編譯,隱式static_cast 轉(zhuǎn)換
            5. CBaseY* pY1 = pD;
            6. printf("CBaseY* pY1 = %x\n", (int)pY1);
            // 成功編譯, 現(xiàn)在 pD1 = pD
            7. CDerived* pD1 = static_cast(pY1);
            8. printf("CDerived* pD1 = %x\n", (int)pD1);
            9.
            10. // reinterpret_cast
            // 成功編譯, 但是 pY2 不是 CBaseY*
            11. CBaseY* pY2 = reinterpret_cast(pD);
            12. printf("CBaseY* pY2 = %x\n", (int)pY2);
            13.
            14. // 無(wú)關(guān)的 static_cast
            15. CBaseY* pY3 = new CBaseY();
            16. printf("CBaseY* pY3 = %x\n", (int)pY3);
            // 成功編譯,盡管 pY3 只是一個(gè) "新 CBaseY()"
            17. CDerived* pD3 = static_cast(pY3);
            18. printf("CDerived* pD3 = %x\n", (int)pD3);
                  ---------------------- 輸出 ---------------------------
            CDerived* pD = 392fb8
            CBaseY* pY1 = 392fbc
            CDerived* pD1 = 392fb8
            CBaseY* pY2 = 392fb8
            CBaseY* pY3 = 390ff0
            CDerived* pD3 = 390fec

            注意:在將CDerived*用隱式 static_cast<>轉(zhuǎn)換到CBaseY*(第5行)時(shí),結(jié)果是(指向)CDerived*(的指針向后) 偏移了4(個(gè)字節(jié))(譯注:4為int類型在內(nèi)存中所占字節(jié)數(shù))。為了知道static_cast<> 實(shí)際如何,我們不得不要來(lái)看一下CDerived的內(nèi)存布局。

            CDerived的內(nèi)存布局(Memory Layout)



            如圖所示,CDerived的內(nèi)存布局包括兩個(gè)對(duì)象,CBaseX 和 CBaseY,編譯器也知道這一點(diǎn)。因此,當(dāng)你將CDerived* 轉(zhuǎn)換到 CBaseY*時(shí),它給指針添加4個(gè)字節(jié),同時(shí)當(dāng)你將CBaseY*轉(zhuǎn)換到CDerived*時(shí),它給指針減去4。然而,甚至它即便不是一個(gè)CDerived你也可以這樣做。
            當(dāng)然,這個(gè)問(wèn)題只在如果你做了多繼承時(shí)發(fā)生。在你將CDerived轉(zhuǎn)換 到 CBaseX時(shí)static_cast<> 和 reinterpret_cast<>是沒(méi)有區(qū)別的。

            情況3:void*之間的向前和向后轉(zhuǎn)換

            因?yàn)槿魏沃羔樋梢员晦D(zhuǎn)換到void*,而void*可以被向后轉(zhuǎn)換到任何指針(對(duì)于static_cast<> 和 reinterpret_cast<>轉(zhuǎn)換都可以這樣做),如果沒(méi)有小心處理的話錯(cuò)誤可能發(fā)生。

                CDerived* pD = new CDerived();
            printf("CDerived* pD = %x\n", (int)pD);

            CBaseY* pY = pD; // 成功編譯, pY = pD + 4
            printf("CBaseY* pY = %x\n", (int)pY);

            void* pV1 = pY; //成功編譯, pV1 = pY
            printf("void* pV1 = %x\n", (int)pV1);

            // pD2 = pY, 但是我們預(yù)期 pD2 = pY - 4
            CDerived* pD2 = static_cast(pV1);
            printf("CDerived* pD2 = %x\n", (int)pD2);
            // 系統(tǒng)崩潰
            // pD2->bar();

                    ---------------------- 輸出 ---------------------------
            CDerived* pD = 392fb8
            CBaseY* pY = 392fbc
            void* pV1 = 392fbc
            CDerived* pD2 = 392fbc

            一旦我們已經(jīng)轉(zhuǎn)換指針為void*,我們就不能輕易將其轉(zhuǎn)換回原類。在上面的例子中,從一個(gè)void* 返回CDerived*的唯一方法是將其轉(zhuǎn)換為CBaseY*然后再轉(zhuǎn)換為CDerived*。
            但是如果我們不能確定它是CBaseY* 還是 CDerived*,這時(shí)我們不得不用dynamic_cast<> 或typeid[2]。

            注釋:
            1. dynamic_cast<>,從另一方面來(lái)說(shuō),可以防止一個(gè)泛型CBaseY* 被轉(zhuǎn)換到CDerived*。
            2. dynamic_cast<>需要類成為多態(tài),即包括“虛”函數(shù),并因此而不能成為void*。
            參考:
            1. [MSDN] C++ Language Reference -- Casting
            2. Nishant Sivakumar, Casting Basics - Use C++ casts in your VC++.NET programs
            3. Juan Soulie, C++ Language Tutorial: Type Casting

            posted @ 2006-12-14 23:20 平凡的天才 閱讀(1335) | 評(píng)論 (2)編輯 收藏

            自己一直以為輸出重載非常簡(jiǎn)單,所以從來(lái)沒(méi)有親手寫過(guò),今天看到一本上上面應(yīng)該這方面的介紹,就忍不住試了一下,果然問(wèn)題百出,
            在6.0中要重載<<時(shí),不能使用如下的頭文件:
            #include<iostream>
            using namespace std;
            而應(yīng)該使用程序代碼中所用的形式,具體原因我沒(méi)有深入研究,望高人指點(diǎn)

            #include<iostream.h>
            //using namespace std;

            class Rational
            {
            public:
            ?Rational(int numerator=0,int denominator=1)
            ?{
            ??n=numerator;
            ??d=denominator;
            ?}

            private:
            ?int n,d;

            friend ostream& operator<<(ostream& s,const Rational& r);
            };

            ostream& operator<<(ostream& s,const Rational& r)
            {
            ?s<<r.n<<'/'<<r.d;
            ?return s;
            }


            int main()
            {
            ?Rational rTemp;
            ?cout<<rTemp<<endl;

            ?return 1;
            }

            posted @ 2006-12-14 22:58 平凡的天才 閱讀(795) | 評(píng)論 (1)編輯 收藏

            利用MFC的Csocket類實(shí)現(xiàn)網(wǎng)絡(luò)通信

            Mail

              近年來(lái),利用Internet進(jìn)行網(wǎng)際間通訊,在WWW瀏 覽、FTP、Gopher這些常規(guī)服務(wù),以及在網(wǎng)絡(luò)電話、多媒體會(huì)議等這些對(duì)實(shí)時(shí)性要求嚴(yán)格 的應(yīng)用中成為研究的熱點(diǎn),而且已經(jīng)是必需的了。Windows環(huán)境下進(jìn)行通訊程序設(shè)計(jì)的最基本方法是應(yīng)用Windows Sockets實(shí)現(xiàn)進(jìn)程間的通訊,為此微軟提供了大量基于Windows Sockets的通訊API,如WinSockAPI、WinInetAPI和ISAPI,并一直致力于開(kāi)發(fā)更快、 更容易的通訊API,將其和MFC集成在一起以使通訊編程越來(lái)越容易。本實(shí)例重點(diǎn)介紹使用MFC的CSocket類編寫網(wǎng)絡(luò)通訊程序的方法,并通過(guò)使用CSocket類實(shí)現(xiàn)了網(wǎng)絡(luò)聊天程序。程序編譯運(yùn)行后的界面效果如圖一所示:

              一、實(shí)現(xiàn)方法

              微軟的MFC把復(fù)雜的WinSock API函數(shù)封裝到類里,這使得編寫網(wǎng)絡(luò)應(yīng)用程序更容易。CAsyncSocket類逐個(gè)封裝了WinSock API,為高級(jí)網(wǎng)絡(luò)程序員 提供了更加有力而靈活的方法。這個(gè)類基于程序員了解網(wǎng)絡(luò)通訊的假設(shè),目的是為了在MFC中使用WinSock,程序員有責(zé)任處理諸如阻塞、字節(jié)順序和在Unicode與MBCS 間轉(zhuǎn)換字符的任務(wù)。為了給程序員提供更方便的接口以自動(dòng)處理這些任務(wù),MFC給出 了CSocket類,這個(gè)類是由CAsyncSocket類繼承下來(lái)的,它提供了比CAsyncSocket更高層的WinSock API接口。Csocket類和CsocketFile類可以與Carchive類一起合作來(lái)管理發(fā)送和接收的數(shù)據(jù),這使管理數(shù)據(jù)收發(fā)更加便利。CSocket對(duì)象提供阻塞模式,這對(duì)于Carchive的同步操作是至關(guān)重要的。阻塞函數(shù)(如Receive()、Send()、ReceiveFrom()、SendTo() 和Accept())直到操作完成后才返回控制權(quán),因此如果需要低層控制和高效率,就使用CasyncSock類;如果需要方便,則可使用Csocket類。

              一些網(wǎng)絡(luò)應(yīng)用程序(如網(wǎng)絡(luò)電話、多媒體會(huì)議工具)對(duì)實(shí)時(shí)性要求非常強(qiáng),要求能夠直接應(yīng)用WinSock發(fā)送和接收數(shù)據(jù)。為了充分利用MFC 的優(yōu)勢(shì),首選方案應(yīng)當(dāng)是MFC中的CAsyncSocket類或CSocket類,這兩個(gè)類完全封裝了WinSock API,并提供更多的便利。本實(shí)例介紹應(yīng)用這兩個(gè)類的編程模型,并引出相關(guān)的成員函數(shù)與一些概念的解釋。

              CSocket類是由CAsyncSocket繼承而來(lái)的,事實(shí)上,在MFC中CAsyncSocket 逐個(gè)封裝了WinSock API,每個(gè)CAsyncSocket對(duì)象代表一個(gè)Windows Socket對(duì)象,使用CAsyncSocket 類要求程序員對(duì)網(wǎng)絡(luò)編程較為熟悉。相比起來(lái),CSocket類是CAsyncSocket的派生類, 繼承了它封裝的WinSock API。

              一個(gè)CSocket對(duì)象代表了一個(gè)比CAsyncSocket對(duì)象更高層次的Windows Socket的抽象,CSocket類與CSocketFile類和CArchive類一起工作來(lái)發(fā)送和接收數(shù)據(jù),因此使用它更加容易使用。CSocket對(duì)象提供阻塞模式,因?yàn)樽枞?能對(duì)于CArchive的同步操作是至關(guān)重要的。在這里有必要對(duì)阻塞的概念作一解釋: 一個(gè)socket可以處于"阻塞模式"或"非阻塞模式",當(dāng)一個(gè)套接字處于阻塞模式(即同步操作)時(shí),它的阻塞函數(shù)直到操作完成才會(huì)返回控制權(quán),之所以稱為阻塞是因?yàn)榇颂捉幼值淖枞瘮?shù)在完成操作返回之前什么也不能做。如果一個(gè)socket處于非阻塞模式(即異步操作),則會(huì)被調(diào)用函數(shù)立即返回。在CAsyncSocket類中可以用GetLastError 成員函數(shù)查詢最后的錯(cuò)誤,如果錯(cuò)誤是WSAEWOULDBLOCK則說(shuō)明有阻塞,而CSocket絕不會(huì)返回WSAEWOULDBLOCK,因?yàn)樗约汗芾碜枞N④浗ㄗh盡量使用非阻塞模式,通過(guò)網(wǎng)絡(luò)事件的發(fā)生而通知應(yīng)用程序進(jìn)行相應(yīng)的處理。但在CSocket類中,為了利用CArchive 處理通訊中的許多問(wèn)題和簡(jiǎn)化編程,它的一些成員函數(shù)總是具有阻塞性質(zhì)的,這是因?yàn)镃Archive類需要同步的操作。

              在Win32環(huán)境下,如果要使用具有阻塞性質(zhì)的套接字,應(yīng)該放在獨(dú)立的工作線程中處理,利用多線程的方法使阻塞不至于干擾其他線程,也不會(huì)把CPU時(shí)間浪費(fèi)在阻塞上。多線程的方法既可以使程序員享受CSocket帶 來(lái)的簡(jiǎn)化編程的便利,也不會(huì)影響用戶界面對(duì)用戶的反應(yīng)。

              CAsyncSocket類編程模型

              在一個(gè)MFC應(yīng)用程序中,要想輕松處理多個(gè)網(wǎng) 絡(luò)協(xié)議,而又不犧牲靈活性時(shí),可以考慮使用CAsyncSocket類,它的效率比CSocket 類要高。CAsyncSocket類針對(duì)字節(jié)流型套接字的編程模型簡(jiǎn)述如下:

              1、構(gòu)造一個(gè)CAsyncSocket對(duì)象,并用這個(gè) 對(duì)象的Create成員函數(shù)產(chǎn)生一個(gè)Socket句柄。可以按如下兩種方法構(gòu)造:


            CAsyncSocket sock; //使用默認(rèn)參數(shù)產(chǎn)生一個(gè)字節(jié)流套接字
            Sock.Create();

              或在指定端口號(hào)產(chǎn)生一個(gè)數(shù)據(jù)報(bào)套接字


            CAsyncSocket*pSocket=newCAsyncSocket;
            intnPort=27;
            pSocket->Create(nPort,SOCK-DGRAM);

              第一種方法在棧上產(chǎn)生一個(gè)CAsyncSocket對(duì)象, 而第二種方法在堆上產(chǎn)生CAsyncSocket對(duì)象;第一種方法中Create()成員函數(shù)用缺省參數(shù)產(chǎn)生一個(gè)字節(jié)流套接字,第二種方法中用Create()成員函數(shù)在指定的端口產(chǎn)生一個(gè)數(shù)字報(bào)套接字。Create()函數(shù)的原型為:


            BOOL Create( UINT nSocketPort = 0, int nSocketType = SOCK_STREAM,
            LPCTSTR lpszSocketAddress = NULL );

              該函數(shù)的參數(shù)有:

              1)端口,UINT類型。注意:如果是服務(wù)方,則使 用一個(gè)眾所周知的端口供服務(wù)方連接;如果是客戶方,典型做法是接受默認(rèn)參數(shù),使 套接字可以自主選擇一個(gè)可用端口;

              2)socket 類型,可以是SOCK-STREAM(默認(rèn)值,字節(jié)流)或SOCK-DGRAM(數(shù)據(jù)報(bào));

              3)socket的地址,例如"ftp.gliet.edu.cn"或"202.193.64.33"。

              2、如是客戶方程序,用CAsyncSocket∷Connect()成員函數(shù)連接到服務(wù)方;如是服務(wù)方程序,用CAsyncSocket∷Listen()成員函數(shù)開(kāi)始 監(jiān)聽(tīng),一旦收到連接請(qǐng)求,則調(diào)用CAsyncSocket∷Accept()成員函數(shù)開(kāi)始接收。注意:CAsyncSocket ∷Accept()成員函數(shù)要用一個(gè)新的并且是空的CAsyncSocket對(duì)象作為它的參數(shù),這里所說(shuō) 的"空的"指的是這個(gè)新對(duì)象還沒(méi)有調(diào)用Create()成員函數(shù)。

              3、調(diào)用其他的CAsyncSocket類的Receive()、ReceiveFrom()、Send()和SendTo()等成員函數(shù)進(jìn)行數(shù)據(jù)通信。

              4、通訊結(jié)束后,銷毀CAsyncSocket對(duì)象。如果是在棧上產(chǎn)生的CAsyncSocket對(duì)象,則對(duì)象超出定義的范圍時(shí)自動(dòng)被析構(gòu);如果是在堆上產(chǎn)生,也就是用了new這個(gè)操作符,則必須使用delete操作符銷毀CAsyncSocket 對(duì)象。

              CSocket類編程模型

              使用CSocket對(duì)象涉及CArchive和CSocketFile 類對(duì)象。以下介紹的針對(duì)字節(jié)流型套接字的操作步驟中,只有第3步對(duì)于客戶方和服務(wù)方操作是不同的,其他步驟都相同。

              1、構(gòu)造一個(gè)CSocket對(duì)象。

              2、使用這個(gè)對(duì)象的Create()成員函數(shù)產(chǎn)生一個(gè)socket對(duì)象。在客戶方程序中,除非需要數(shù)據(jù)報(bào)套接字,Create()函數(shù)一般情況下應(yīng)該使用默認(rèn)參數(shù)。而對(duì)于服務(wù)方程序,必須在調(diào)用Create時(shí)指定一個(gè)端口。需要注意的是,Carchive類對(duì)象不能與數(shù)據(jù)報(bào)(UDP)套接字一起工作,因此對(duì)于數(shù)據(jù)報(bào)套接字,CAsyncSocket和CSocket 的使用方法是一樣的。

              3、如果是客戶方套接字,則調(diào)用CAsyncSocket ∷Connect()函數(shù)與服務(wù)方套接字連接;如果是服務(wù)方套接字,則調(diào)用CAsyncSocket∷Listen()開(kāi)始監(jiān)聽(tīng)來(lái)自客戶方的連接請(qǐng)求,收到連接請(qǐng)求后,調(diào)用CAsyncSocket∷Accept()函數(shù)接受請(qǐng)求,建立連接。請(qǐng)注意Accept()成員函數(shù)需要一個(gè)新的并且為空的CSocket對(duì)象作為它的參數(shù),解釋同上。

              4、產(chǎn)生一個(gè)CSocketFile對(duì)象,并把它與CSocket 對(duì)象關(guān)聯(lián)起來(lái)。

              5、為接收和發(fā)送數(shù)據(jù)各產(chǎn)生一個(gè)CArchive 對(duì)象,把它們與CSocketFile對(duì)象關(guān)聯(lián)起來(lái)。切記CArchive是不能和數(shù)據(jù)報(bào)套接字一起工作的。

              6、使用CArchive對(duì)象的Read()、Write()等函數(shù)在客戶與服務(wù)方傳送數(shù)據(jù)。

              7、通訊完畢后,銷毀CArchive、CSocketFile和CSocket對(duì)象。

              二、編程步驟

              1、 啟動(dòng)Visual C++6.0,生成一個(gè)基于對(duì)話框架的應(yīng)用程序,將該程序命名為"Test";

              2、 按照?qǐng)D一所示的效果圖設(shè)置對(duì)話框的界面;

              3、 使用Class Wizard為應(yīng)用程序的按鈕添加鼠標(biāo)單擊消息響應(yīng)函數(shù);

              4、 使用Class Wizard在應(yīng)用程序中定義新類CNewSocket,其基類選擇為CSocket;

              5、 添加代碼,編譯運(yùn)行程序。

            三、程序代碼

            ////////////////////////////////////////////////// NewSocket.h : header file
            #if !defined(AFX_NEWSOCKET_H__8CE2ED73_1D56_11D3_9928_00A0C98F3E85__INCLUDED_)
            #define AFX_NEWSOCKET_H__8CE2ED73_1D56_11D3_9928_00A0C98F3E85__INCLUDED_
            #if _MSC_VER >= 1000
            #pragma once
            #endif // _MSC_VER >= 1000
            class CTestDlg;
            #include <afxsock.h>

            class CNewSocket : public CSocket
            {
            // Attributes
            public:

            // Operations
            public:
            CNewSocket();
            virtual ~CNewSocket();

            // Overrides
            public:
            int m_Status;
            void GetDlg(CTestDlg *dlg);
            CTestDlg *m_dlg;
            // ClassWizard generated virtual function overrides
            //{{AFX_VIRTUAL(CNewSocket)
            public:
            virtual void OnAccept(int nErrorCode);
            virtual void OnReceive(int nErrorCode);
            virtual void OnClose(int nErrorCode);
            //}}AFX_VIRTUAL
            // Generated message map functions
            //{{AFX_MSG(CNewSocket)
            // NOTE - the ClassWizard will add and remove member functions here.
            //}}AFX_MSG
            // Implementation
            protected:
            };
            #endif

            //////////////////////////////////////////////////////// NewSocket.cpp : implementation file
            #include "stdafx.h"
            #include "Test.h"
            #include "NewSocket.h"
            #include "TestDlg.h"
            #ifdef _DEBUG
            #define new DEBUG_NEW
            #undef THIS_FILE
            static char THIS_FILE[] = __FILE__;
            #endif

            CNewSocket::CNewSocket()
            {}

            CNewSocket::~CNewSocket()
            {}

            #if 0
            BEGIN_MESSAGE_MAP(CNewSocket, CSocket)
            //{{AFX_MSG_MAP(CNewSocket)
            //}}AFX_MSG_MAP
            END_MESSAGE_MAP()
            #endif // 0

            void CNewSocket::OnAccept(int nErrorCode)
            {
             if (m_dlg->m_ClientSocket==NULL) m_dlg->OnAccept();
             CSocket::OnAccept(nErrorCode);
            }

            void CNewSocket::OnReceive(int nErrorCode)
            {
             m_dlg->OnReceive();
             CSocket::OnReceive(nErrorCode);
            }

            void CNewSocket::GetDlg(CTestDlg *dlg)
            {
             m_dlg=dlg;
            }

            void CNewSocket::OnClose(int nErrorCode)
            {
             m_dlg->OnClose();
             CSocket::OnClose(nErrorCode);
            }

            ///////////////////////////////////////////////////////////////// TestDlg.h : header file
            #if !defined(AFX_TESTDLG_H__EDDDE196_1BF1_11D3_BE77_0000B454AEE4__INCLUDED_)
            #define AFX_TESTDLG_H__EDDDE196_1BF1_11D3_BE77_0000B454AEE4__INCLUDED_
            #if _MSC_VER >= 1000
            #pragma once
            #endif // _MSC_VER >= 1000
            #include "NewSocket.h"

            class CTestDlg : public CDialog
            {
             // Construction
             public:
              void SocketReset();
              void OnClose();
              void OnReceive();
              void OnAccept();
              CSocketFile *m_file;
              CArchive *m_arOut;
              CArchive *m_arIn;
              CNewSocket* m_ServerSocket;
              CNewSocket* m_ClientSocket;
              CTestDlg(CWnd* pParent = NULL); // standard constructor
              // Dialog Data
              //{{AFX_DATA(CTestDlg)
              enum { IDD = IDD_TEST_DIALOG };
              CString m_Info;
              CString m_Output;
              CString m_Input;
              CString m_Connect;
              CString m_IPAddress;
              UINT m_Port;
              int m_Status;
              //}}AFX_DATA
              // ClassWizard generated virtual function overrides
              //{{AFX_VIRTUAL(CTestDlg)
             protected:
              virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
              //}}AFX_VIRTUAL
              // Implementation
             protected:
              HICON m_hIcon;
              // Generated message map functions
              //{{AFX_MSG(CTestDlg)
              virtual BOOL OnInitDialog();
              afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
              afx_msg void OnPaint();
              afx_msg HCURSOR OnQueryDragIcon();
              afx_msg void OnConnect();
              afx_msg void OnDisconnect();
              afx_msg void OnSend();
              afx_msg void OnServerradio();
              afx_msg void OnClientradio();
              afx_msg void OnSendclear();
              afx_msg void OnReceiveclear();
              //}}AFX_MSG
              DECLARE_MESSAGE_MAP()
             };
            #endif

            //////////////////////////////////////////////////////////////// TestDlg.cpp : implementation file
            #include "stdafx.h"
            #include "Test.h"
            #include "TestDlg.h"
            #include <afxsock.h>
            #ifdef _DEBUG
            #define new DEBUG_NEW
            #undef THIS_FILE
            static char THIS_FILE[] = __FILE__;
            #endif

            class CAboutDlg : public CDialog
            {
             public:
              CAboutDlg();
              // Dialog Data
              //{{AFX_DATA(CAboutDlg)
               enum { IDD = IDD_ABOUTBOX };
              //}}AFX_DATA
              // ClassWizard generated virtual function overrides
              //{{AFX_VIRTUAL(CAboutDlg)
             protected:
              virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
              //}}AFX_VIRTUAL
              // Implementation
             protected:
              //{{AFX_MSG(CAboutDlg)
              //}}AFX_MSG
             DECLARE_MESSAGE_MAP()
            };

            CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
            {
             //{{AFX_DATA_INIT(CAboutDlg)
             //}}AFX_DATA_INIT
            }

            void CAboutDlg::DoDataExchange(CDataExchange* pDX)
            {
             CDialog::DoDataExchange(pDX);
             //{{AFX_DATA_MAP(CAboutDlg)
             //}}AFX_DATA_MAP
            }

            BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
             //{{AFX_MSG_MAP(CAboutDlg)
             // No message handlers
             //}}AFX_MSG_MAP
            END_MESSAGE_MAP()

            CTestDlg::CTestDlg(CWnd* pParent /*=NULL*/)
            : CDialog(CTestDlg::IDD, pParent)
            {
             //{{AFX_DATA_INIT(CTestDlg)
              m_Info = _T("");
              m_Output = _T("");
              m_Input = _T("");
              m_Connect = _T("");
              m_IPAddress = _T("");
              m_Port = 0;
              m_Status = -1;
             //}}AFX_DATA_INIT
             // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
             m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
            }

            void CTestDlg::DoDataExchange(CDataExchange* pDX)
            {
             CDialog::DoDataExchange(pDX);
             //{{AFX_DATA_MAP(CTestDlg)
              DDX_Text(pDX, IDC_OUTPUTEDIT, m_Output);
              DDX_Text(pDX, IDC_INPUTEDIT, m_Input);
              DDX_Text(pDX, IDC_CONNECTEDIT, m_Connect);
              DDX_Text(pDX, IDC_IPADDRESS, m_IPAddress);
              DDV_MaxChars(pDX, m_IPAddress, 15);
              DDX_Text(pDX, IDC_PORT, m_Port);
              DDX_Radio(pDX, IDC_SERVERRADIO, m_Status);
             //}}AFX_DATA_MAP
            }

            BEGIN_MESSAGE_MAP(CTestDlg, CDialog)
            //{{AFX_MSG_MAP(CTestDlg)
             ON_WM_SYSCOMMAND()
             ON_WM_PAINT()
             ON_WM_QUERYDRAGICON()
             ON_BN_CLICKED(IDC_CONNECTBUTTON, OnConnect)
             ON_BN_CLICKED(IDC_DISCONNECTBUTTON, OnDisconnect)
             ON_BN_CLICKED(IDC_SENDBUTTON, OnSend)
             ON_BN_CLICKED(IDC_SERVERRADIO, OnServerradio)
             ON_BN_CLICKED(IDC_CLIENTRADIO, OnClientradio)
             ON_BN_CLICKED(IDC_SENDCLEARBUTTON, OnSendclear)
             ON_BN_CLICKED(IDC_RECEIVECLEARBUTTON, OnReceiveclear)
            //}}AFX_MSG_MAP
            END_MESSAGE_MAP()

            BOOL CTestDlg::OnInitDialog()
            {
             CDialog::OnInitDialog();
             // Add "About..." menu item to system menu.
             // IDM_ABOUTBOX must be in the system command range.
             ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
             ASSERT(IDM_ABOUTBOX < 0xF000);
             CMenu* pSysMenu = GetSystemMenu(FALSE);
             if (pSysMenu != NULL)
             {
              CString strAboutMenu;
              strAboutMenu.LoadString(IDS_ABOUTBOX);
              if (!strAboutMenu.IsEmpty())
              {
               pSysMenu->AppendMenu(MF_SEPARATOR);
               pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
              }
             }
             // Set the icon for this dialog. The framework does this automatically
             // when the application's main window is not a dialog
             SetIcon(m_hIcon, TRUE); // Set big icon
             SetIcon(m_hIcon, FALSE); // Set small icon
             m_Status=-1;
             m_ServerSocket=NULL;
             m_ClientSocket=NULL;
             m_arIn=NULL;
             m_arOut=NULL;
             m_file=NULL;
             m_Connect="";
             m_IPAddress="202.207.243.29";
             m_Port=5000;
             GetDlgItem(IDC_IPADDRESS)->EnableWindow(FALSE);
             GetDlgItem(IDC_PORT)->EnableWindow(FALSE);
             UpdateData(FALSE);
             return TRUE; // return TRUE unless you set the focus to a control
            }

            void CTestDlg::OnSysCommand(UINT nID, LPARAM lParam)
            {
             if ((nID & 0xFFF0) == IDM_ABOUTBOX)
             {
              CAboutDlg dlgAbout;
              dlgAbout.DoModal();
             }
             else
             {
              CDialog::OnSysCommand(nID, lParam);
             }
            }

            // If you add a minimize button to your dialog, you will need the code below
            // to draw the icon. For MFC applications using the document/view model,
            // this is automatically done for you by the framework.
            void CTestDlg::OnPaint()
            {
             if (IsIconic())
             {
              CPaintDC dc(this); // device context for painting
              SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
              // Center icon in client rectangle
              int cxIcon = GetSystemMetrics(SM_CXICON);
              int cyIcon = GetSystemMetrics(SM_CYICON);
              CRect rect;
              GetClientRect(&rect);
              int x = (rect.Width() - cxIcon + 1) / 2;
              int y = (rect.Height() - cyIcon + 1) / 2;
              // Draw the icon
              dc.DrawIcon(x, y, m_hIcon);
             }
             else
             {
              CDialog::OnPaint();
             }
            }

            // The system calls this to obtain the cursor to display while the user drags
            // the minimized window.
            HCURSOR CTestDlg::OnQueryDragIcon()
            {
             return (HCURSOR) m_hIcon;
            }

            void CTestDlg::OnConnect()
            {
             CString msg;
             UpdateData(TRUE);
             if (m_Status==0 ) //server
             {
              if ( m_ServerSocket!=NULL)
              {
               m_Connect="Please disconnect!";
               UpdateData(FALSE);
              }
              else
              {
               m_Connect="Waiting for Client...";
               UpdateData(FALSE);
               if(!AfxSocketInit())
               {
                MessageBox("WindowsSocket initial failed!","Send",MB_ICONSTOP);
                return;
               }
               m_ServerSocket=new CNewSocket;
               m_ServerSocket->m_Status=m_Status;
               m_ServerSocket->GetDlg(this);
               if(!m_ServerSocket->Create(m_Port))
                 MessageBox("SendSocket create failed!", "Send",MB_ICONSTOP);
               else
               {
                m_ServerSocket->Listen();
               }
              }
             }
             else
             {
              if (m_Status==1)
              {
               if (m_ClientSocket!=NULL)
               {
                m_Connect="Please disconnect!";
                UpdateData(FALSE);
               }
               else
               {
                m_Connect="Connect to the Server...";
                UpdateData(FALSE);
                if(!AfxSocketInit())
                {
                 MessageBox("WindowsSocket initial failed!","Receive",MB_ICONSTOP);
                 return;
                }  
                m_ClientSocket=new CNewSocket;
                m_ClientSocket->GetDlg(this);
                m_ClientSocket->m_Status=m_Status;
                if(!m_ClientSocket->Create())
                {
                 MessageBox("ReceiveSocket create failed!","Receive",MB_ICONSTOP);
                 return;
                }
                else
                {
                 if (!m_ClientSocket->Connect(m_IPAddress,m_Port))
                 {
                  CString str=m_Connect;
                  SocketReset();
                  m_Connect=str;
                  m_Connect+="Error!";
                  UpdateData(FALSE);
                 }
                 else
                 {
                  m_Connect+="OK!";
                  m_file=new CSocketFile(m_ClientSocket);
                  m_arIn=new CArchive(m_file, CArchive::load);
                  m_arOut=new CArchive(m_file, CArchive::store);
                 }
                 UpdateData(FALSE);
                }
               }
              }
             }
             if (m_Status==-1)
             {
              msg="Please choose the status!";
              AfxMessageBox(msg);
             }
            }

            void CTestDlg::OnSend()
            {
             if (m_arOut)
             {
              if (m_Status==0)
              {
               UpdateData(TRUE);
               *m_arOut<<m_Output;
               m_arOut->Flush();
              }
              else
              {
               UpdateData(TRUE);
               *m_arOut<<m_Output;
               m_arOut->Flush();
              }
             }
             else AfxMessageBox("Not connected!");
            }

            void CTestDlg::OnAccept()
            {
             m_Connect+="OK!";
             UpdateData(FALSE);
             m_ClientSocket=new CNewSocket;
             m_ClientSocket->GetDlg(this);
             m_ServerSocket->Accept(*m_ClientSocket);
             m_ClientSocket->m_Status=m_ServerSocket->m_Status;
             m_file=new CSocketFile(m_ClientSocket);
             m_arIn=new CArchive(m_file, CArchive::load);
             m_arOut=new CArchive(m_file, CArchive::store);
            }

            void CTestDlg::OnReceive()
            {
             *m_arIn>>m_Input;
             UpdateData(FALSE);
            }

            void CTestDlg::OnDisconnect()
            {
             if (m_arOut!=NULL)
             {
              SocketReset();
              m_Connect="Disconnected!";
              UpdateData(FALSE);
             }
            }

            void CTestDlg::OnClose()
            {
             if (m_ClientSocket->m_Status==0) m_Connect="Client ";
             else m_Connect="Server ";
             m_Connect+="has disconnected!";
             UpdateData(FALSE);
            }

            void CTestDlg::SocketReset()
            {
             if (m_arIn!=NULL)
             {
              delete m_arIn;
              m_arIn=NULL;
             }
             if (m_arOut!=NULL)
             {
              delete m_arOut;
              m_arOut=NULL;
             }
             if (m_file!=NULL)
             {
              delete m_file;
              m_file=NULL;
             }
             if (m_ClientSocket!=NULL)
             {
              delete m_ClientSocket;
              m_ClientSocket=NULL;
             }
             if (m_ServerSocket!=NULL)
             {
              delete m_ServerSocket;
              m_ServerSocket=NULL;
             }
             m_Connect="";
             UpdateData(FALSE);
            }

            void CTestDlg::OnServerradio()
            {
             UpdateData(TRUE);
             GetDlgItem(IDC_IPADDRESS)->EnableWindow(FALSE);
             GetDlgItem(IDC_PORT)->EnableWindow(TRUE);
             UpdateData(FALSE);
            }

            void CTestDlg::OnClientradio()
            {
             UpdateData(TRUE);
             GetDlgItem(IDC_IPADDRESS)->EnableWindow(TRUE);
             GetDlgItem(IDC_PORT)->EnableWindow(TRUE);
             UpdateData(FALSE);
            }

            void CTestDlg::OnSendclear()
            {
             m_Output="";
             UpdateData(FALSE);
            }

            void CTestDlg::OnReceiveclear()
            {
             m_Input="";
             UpdateData(FALSE);
            }

              四、小結(jié)

              本實(shí)例介紹了CAsyncSocket、CSocket類,并通過(guò)使用CSocket類實(shí)現(xiàn)了網(wǎng)絡(luò)聊天程序。讀者朋友還可以通過(guò)MFC CArchive 對(duì)象進(jìn)行信息的接發(fā)操作,使得網(wǎng)絡(luò)傳輸如同使用MFC的文檔連載協(xié)議(Serialization protocol),簡(jiǎn)捷易用。

            posted @ 2006-12-10 14:51 平凡的天才 閱讀(2033) | 評(píng)論 (0)編輯 收藏

            在C語(yǔ)言編程中,static的一個(gè)作用是信息屏蔽!

            比方說(shuō),你自己定義了一個(gè)文件?--?該文件中有一系列的函數(shù)以及變量的聲明和定義!

            你希望該文件中的一些函數(shù)和變量只能被該文件中的函數(shù)使用,那么,你可以在該函數(shù)、變量的前面加上static,代表他們只能被當(dāng)前文件中的函數(shù)使用!


            而在C++中,用static來(lái)作為信息屏蔽就顯得沒(méi)有必要了!因?yàn)椋珻++有了信息屏蔽的利器?--?class機(jī)制!

            類中的private屬性的變量和函數(shù)就對(duì)外禁止訪問(wèn)!


            然后是C/C++通用的函數(shù)作用域的static型的變量!其目的,也是為了信息的屏蔽!


            int?fun()?{
            ???static?int?a?=?1;
            ???a++;
            }

            在第一次進(jìn)入這個(gè)函數(shù)的時(shí)候,變量a被初始化為1!并接著自增1!

            以后每次進(jìn)入該函數(shù),a就不會(huì)被再次初始化了,僅進(jìn)行自增1的操作!

            在static發(fā)明前,要達(dá)到同樣的功能,則只能使用全局變量:

            int?a?=?1;

            int?fun()?{
            ???a++;
            }

            那么,a的值就有可能被其他函數(shù)所改變!



            最后,說(shuō)說(shuō)類中的static變量和函數(shù)。


            這種存儲(chǔ)屬性的變量和函數(shù)是同一種類的不同實(shí)例之間通信的橋梁!


            #include?<iostream>
            using?namespace?std;

            class?A?{
            public:
            ????static?int?num;????//????統(tǒng)計(jì)創(chuàng)建了多少個(gè)實(shí)例
            ????A?()?{num++};????//????每創(chuàng)建一個(gè)實(shí)例,就讓num自增1

            ????//????返回通過(guò)構(gòu)造函數(shù)所創(chuàng)建過(guò)的A類實(shí)例的數(shù)目
            ????static?int?how_many_instance()?{
            ????????return?num;
            ????}
            }

            static?A::num?=?0;????//????需要在類申明的外部單獨(dú)初始化!


            int?main()?{
            ????cout?<<?A::how_many_instance()?<<?endl;
            ????A?a,?b,?c,?d;
            ????cout?<<?A::how_many_instance()?<<?endl;
            ????system("pause");
            }


            一般,在類內(nèi)部,是通過(guò)static屬性的函數(shù),訪問(wèn)static屬性的變量!

            補(bǔ)充一點(diǎn),在類中,static型的成員函數(shù),由于是類所擁有的,而不是具體對(duì)象所有的,這一點(diǎn)對(duì)于windows的回調(diào)機(jī)制非常有用。
            因?yàn)閷?duì)于回調(diào)函數(shù)而言,windows不會(huì)借助任何對(duì)象去調(diào)用它,也就不會(huì)傳遞this指針,那么對(duì)于一般成員函數(shù)作為回調(diào)函數(shù)的后果,就是堆棧中有一個(gè)隨機(jī)的變量會(huì)成為this指針,這當(dāng)然會(huì)引發(fā)程序的崩潰。
            而static函數(shù),由于是整個(gè)類的,屏蔽了this指針。因此,如果成員函數(shù)作為回調(diào)函數(shù),就應(yīng)該用static去修飾它。

            posted @ 2006-12-09 16:02 平凡的天才 閱讀(11681) | 評(píng)論 (4)編輯 收藏

            關(guān)于Debug和Release之本質(zhì)區(qū)別??????????????????????????????????????

            經(jīng)常在 CSDN 上看見(jiàn)有人問(wèn) Debug 運(yùn)行正常但 Release 失敗的問(wèn)題。以往的討論往往是
            經(jīng)驗(yàn)性的,并沒(méi)有指出會(huì)這樣的真正原因是什么,要想找出真正的原因通常要憑運(yùn)氣。最
            近我看了一些這方面的書(shū),又參考了 CSDN 上的一些帖子,然后深入研究了一下關(guān)于二者
            的不同。以下是我的一些體會(huì),拿來(lái)與大家共享。
            --------------------------------------
            本文主要包含如下內(nèi)容:
            1. Debug 和 Release 編譯方式的本質(zhì)區(qū)別
            2. 哪些情況下 Release 版會(huì)出錯(cuò)
            2. 怎樣“調(diào)試” Release 版的程序
            --------------------------------------

            ??????????? 關(guān)于Debug和Release之本質(zhì)區(qū)別的討論

            一、Debug 和 Release 編譯方式的本質(zhì)區(qū)別

            ??? Debug 通常稱為調(diào)試版本,它包含調(diào)試信息,并且不作任何優(yōu)化,便于程序員調(diào)試程
            序。Release 稱為發(fā)布版本,它往往是進(jìn)行了各種優(yōu)化,使得程序在代碼大小和運(yùn)行速度
            上都是最優(yōu)的,以便用戶很好地使用。
            ??? Debug 和 Release 的真正秘密,在于一組編譯選項(xiàng)。下面列出了分別針對(duì)二者的選項(xiàng)
            (當(dāng)然除此之外還有其他一些,如/Fd /Fo,但區(qū)別并不重要,通常他們也不會(huì)引起 Rele
            ase 版錯(cuò)誤,在此不討論)

            Debug 版本:
            ?/MDd /MLd 或 /MTd?? 使用 Debug runtime library(調(diào)試版本的運(yùn)行時(shí)刻函數(shù)庫(kù))
            ?/Od???????????????? 關(guān)閉優(yōu)化開(kāi)關(guān)
            ?/D "_DEBUG"???????? 相當(dāng)于 #define _DEBUG,打開(kāi)編譯調(diào)試代碼開(kāi)關(guān)(主要針對(duì)
            ???????????????????? assert函數(shù))
            ?/ZI???????????????? 創(chuàng)建 Edit and continue(編輯繼續(xù))數(shù)據(jù)庫(kù),這樣在調(diào)試過(guò)
            ???????????????????? 程中如果修改了源代碼不需重新編譯
            ?/GZ???????????????? 可以幫助捕獲內(nèi)存錯(cuò)誤
            ?/Gm???????????????? 打開(kāi)最小化重鏈接開(kāi)關(guān),減少鏈接時(shí)間

            Release 版本:
            ?/MD /ML 或 /MT????? 使用發(fā)布版本的運(yùn)行時(shí)刻函數(shù)庫(kù)
            ?/O1 或 /O2????????? 優(yōu)化開(kāi)關(guān),使程序最小或最快
            ?/D "NDEBUG"???????? 關(guān)閉條件編譯調(diào)試代碼開(kāi)關(guān)(即不編譯assert函數(shù))
            ?/GF???????????????? 合并重復(fù)的字符串,并將字符串常量放到只讀內(nèi)存,防止
            ???????????????????? 被修改

            ??? 實(shí)際上,Debug 和 Release 并沒(méi)有本質(zhì)的界限,他們只是一組編譯選項(xiàng)的集合,編譯
            器只是按照預(yù)定的選項(xiàng)行動(dòng)。事實(shí)上,我們甚至可以修改這些選項(xiàng),從而得到優(yōu)化過(guò)的調(diào)
            試版本或是帶跟蹤語(yǔ)句的發(fā)布版本。

            二、哪些情況下 Release 版會(huì)出錯(cuò)

            ??? 有了上面的介紹,我們?cè)賮?lái)逐個(gè)對(duì)照這些選項(xiàng)看看 Release 版錯(cuò)誤是怎樣產(chǎn)生的

            ?1. Runtime Library:鏈接哪種運(yùn)行時(shí)刻函數(shù)庫(kù)通常只對(duì)程序的性能產(chǎn)生影響。調(diào)試版本
            的 Runtime Library 包含了調(diào)試信息,并采用了一些保護(hù)機(jī)制以幫助發(fā)現(xiàn)錯(cuò)誤,因此性能
            不如發(fā)布版本。編譯器提供的 Runtime Library 通常很穩(wěn)定,不會(huì)造成 Release 版錯(cuò)誤
            ;倒是由于 Debug 的 Runtime Library 加強(qiáng)了對(duì)錯(cuò)誤的檢測(cè),如堆內(nèi)存分配,有時(shí)會(huì)出
            現(xiàn) Debug 有錯(cuò)但 Release 正常的現(xiàn)象。應(yīng)當(dāng)指出的是,如果Debug有錯(cuò),即使 Release
            正常,程序肯定是有 Bug 的,只不過(guò)可能是 Release版的某次運(yùn)行沒(méi)有表現(xiàn)出來(lái)而已。


            ?2. 優(yōu)化:這是造成錯(cuò)誤的主要原因,因?yàn)殛P(guān)閉優(yōu)化時(shí)源程序基本上是直接翻譯的,而打
            開(kāi)優(yōu)化后編譯器會(huì)作出一系列假設(shè)。這類錯(cuò)誤主要有以下幾種:

            ??? (1) 幀指針(Frame Pointer)省略(簡(jiǎn)稱 FPO ):在函數(shù)調(diào)用過(guò)程中,所有調(diào)用信息
            (返回地址、參數(shù))以及自動(dòng)變量都是放在棧中的。若函數(shù)的聲明與實(shí)現(xiàn)不同(參數(shù)、返
            回值、調(diào)用方式),就會(huì)產(chǎn)生錯(cuò)誤————但 Debug 方式下,棧的訪問(wèn)通過(guò) EBP 寄存器
            保存的地址實(shí)現(xiàn),如果沒(méi)有發(fā)生數(shù)組越界之類的錯(cuò)誤(或是越界“不多”),函數(shù)通常能
            正常執(zhí)行;Release 方式下,優(yōu)化會(huì)省略 EBP 棧基址指針,這樣通過(guò)一個(gè)全局指針訪問(wèn)棧
            就會(huì)造成返回地址錯(cuò)誤是程序崩潰。C++ 的強(qiáng)類型特性能檢查出大多數(shù)這樣的錯(cuò)誤,但如
            果用了強(qiáng)制類型轉(zhuǎn)換,就不行了。你可以在 Release 版本中強(qiáng)制加入 /Oy- 編譯選項(xiàng)來(lái)關(guān)
            掉幀指針省略,以確定是否此類錯(cuò)誤。此類錯(cuò)誤通常有:

            ???? ● MFC 消息響應(yīng)函數(shù)書(shū)寫錯(cuò)誤。正確的應(yīng)為
            ????? afx_msg LRESULT OnMessageOwn(WPARAM wparam, LPARAM lparam);
            ????? ON_MESSAGE 宏包含強(qiáng)制類型轉(zhuǎn)換。防止這種錯(cuò)誤的方法之一是重定義 ON_MESSAGE
            ?宏,把下列代碼加到 stdafx.h 中(在#include "afxwin.h"之后),函數(shù)原形錯(cuò)誤時(shí)編譯
            會(huì)報(bào)錯(cuò)
            ????? #undef ON_MESSAGE
            ????? #define ON_MESSAGE(message, memberFxn) \
            ????? { message, 0, 0, 0, AfxSig_lwl, \
            ????? (AFX_PMSG)(AFX_PMSGW)(static_cast< LRESULT (AFX_MSG_CALL \
            ????? CWnd::*)(WPARAM, LPARAM) > (&memberFxn) },

            ??? (2) volatile 型變量:volatile 告訴編譯器該變量可能被程序之外的未知方式修改
            (如系統(tǒng)、其他進(jìn)程和線程)。優(yōu)化程序?yàn)榱耸钩绦蛐阅芴岣撸0岩恍┳兞糠旁诩拇嫫?br />中(類似于 register 關(guān)鍵字),而其他進(jìn)程只能對(duì)該變量所在的內(nèi)存進(jìn)行修改,而寄存
            器中的值沒(méi)變。如果你的程序是多線程的,或者你發(fā)現(xiàn)某個(gè)變量的值與預(yù)期的不符而你確
            信已正確的設(shè)置了,則很可能遇到這樣的問(wèn)題。這種錯(cuò)誤有時(shí)會(huì)表現(xiàn)為程序在最快優(yōu)化出
            錯(cuò)而最小優(yōu)化正常。把你認(rèn)為可疑的變量加上 volatile 試試。

            ??? (3) 變量?jī)?yōu)化:優(yōu)化程序會(huì)根據(jù)變量的使用情況優(yōu)化變量。例如,函數(shù)中有一個(gè)未被
            使用的變量,在 Debug 版中它有可能掩蓋一個(gè)數(shù)組越界,而在 Release 版中,這個(gè)變量
            很可能被優(yōu)化調(diào),此時(shí)數(shù)組越界會(huì)破壞棧中有用的數(shù)據(jù)。當(dāng)然,實(shí)際的情況會(huì)比這復(fù)雜得
            多。與此有關(guān)的錯(cuò)誤有:
            ???? ● 非法訪問(wèn),包括數(shù)組越界、指針錯(cuò)誤等。例如
            ???????? void fn(void)
            ???????? {
            ?????????? int i;
            ?????????? i = 1;
            ?????????? int a[4];
            ?????????? {
            ???????????? int j;
            ???????????? j = 1;
            ?????????? }
            ?????????? a[-1] = 1;//當(dāng)然錯(cuò)誤不會(huì)這么明顯,例如下標(biāo)是變量
            ?????????? a[4] = 1;
            ???????? }
            ?????? j 雖然在數(shù)組越界時(shí)已出了作用域,但其空間并未收回,因而 i 和 j 就會(huì)掩蓋越
            界。而 Release 版由于 i、j 并未其很大作用可能會(huì)被優(yōu)化掉,從而使棧被破壞。

            3. _DEBUG 與 NDEBUG :當(dāng)定義了 _DEBUG 時(shí),assert() 函數(shù)會(huì)被編譯,而 NDEBUG 時(shí)不
            被編譯。除此之外,VC++中還有一系列斷言宏。這包括:

            ??? ANSI C 斷言???????? void assert(int expression );
            ??? C Runtime Lib 斷言? _ASSERT( booleanExpression );
            ??????????????????????? _ASSERTE( booleanExpression );
            ??? MFC 斷言??????????? ASSERT( booleanExpression );
            ??????????????????????? VERIFY( booleanExpression );
            ??????????????????????? ASSERT_VALID( pObject );
            ??????????????????????? ASSERT_KINDOF( classname, pobject );
            ??? ATL 斷言??????????? ATLASSERT( booleanExpression );
            ??? 此外,TRACE() 宏的編譯也受 _DEBUG 控制。

            ??? 所有這些斷言都只在 Debug版中才被編譯,而在 Release 版中被忽略。唯一的例外是
            ?VERIFY() 。事實(shí)上,這些宏都是調(diào)用了 assert() 函數(shù),只不過(guò)附加了一些與庫(kù)有關(guān)的
            調(diào)試代碼。如果你在這些宏中加入了任何程序代碼,而不只是布爾表達(dá)式(例如賦值、能
            改變變量值的函數(shù)調(diào)用 等),那么 Release 版都不會(huì)執(zhí)行這些操作,從而造成錯(cuò)誤。初
            學(xué)者很容易犯這類錯(cuò)誤,查找的方法也很簡(jiǎn)單,因?yàn)檫@些宏都已在上面列出,只要利用 V
            C++ 的 Find in Files 功能在工程所有文件中找到用這些宏的地方再一一檢查即可。另外
            ,有些高手可能還會(huì)加入 #ifdef _DEBUG 之類的條件編譯,也要注意一下。
            ??? 順便值得一提的是 VERIFY() 宏,這個(gè)宏允許你將程序代碼放在布爾表達(dá)式里。這個(gè)
            宏通常用來(lái)檢查 Windows API 的返回值。有些人可能為這個(gè)原因而濫用 VERIFY() ,事實(shí)
            上這是危險(xiǎn)的,因?yàn)?VERIFY() 違反了斷言的思想,不能使程序代碼和調(diào)試代碼完全分離
            ,最終可能會(huì)帶來(lái)很多麻煩。因此,專家們建議盡量少用這個(gè)宏。

            4. /GZ 選項(xiàng):這個(gè)選項(xiàng)會(huì)做以下這些事

            ??? (1) 初始化內(nèi)存和變量。包括用 0xCC 初始化所有自動(dòng)變量,0xCD ( Cleared Data
            ) 初始化堆中分配的內(nèi)存(即動(dòng)態(tài)分配的內(nèi)存,例如 new ),0xDD ( Dead Data ) 填充
            已被釋放的堆內(nèi)存(例如 delete ),0xFD( deFencde Data ) 初始化受保護(hù)的內(nèi)存(de
            bug 版在動(dòng)態(tài)分配內(nèi)存的前后加入保護(hù)內(nèi)存以防止越界訪問(wèn)),其中括號(hào)中的詞是微軟建
            議的助記詞。這樣做的好處是這些值都很大,作為指針是不可能的(而且 32 位系統(tǒng)中指
            針很少是奇數(shù)值,在有些系統(tǒng)中奇數(shù)的指針會(huì)產(chǎn)生運(yùn)行時(shí)錯(cuò)誤),作為數(shù)值也很少遇到,
            而且這些值也很容易辨認(rèn),因此這很有利于在 Debug 版中發(fā)現(xiàn) Release 版才會(huì)遇到的錯(cuò)
            誤。要特別注意的是,很多人認(rèn)為編譯器會(huì)用 0 來(lái)初始化變量,這是錯(cuò)誤的(而且這樣很
            不利于查找錯(cuò)誤)。
            ??? (2) 通過(guò)函數(shù)指針調(diào)用函數(shù)時(shí),會(huì)通過(guò)檢查棧指針驗(yàn)證函數(shù)調(diào)用的匹配性。(防止原
            形不匹配)
            ??? (3) 函數(shù)返回前檢查棧指針,確認(rèn)未被修改。(防止越界訪問(wèn)和原形不匹配,與第二
            項(xiàng)合在一起可大致模擬幀指針省略 FPO )

            ??? 通常 /GZ 選項(xiàng)會(huì)造成 Debug 版出錯(cuò)而 Release 版正常的現(xiàn)象,因?yàn)?Release 版中
            未初始化的變量是隨機(jī)的,這有可能使指針指向一個(gè)有效地址而掩蓋了非法訪問(wèn)。

            除此之外,/Gm /GF 等選項(xiàng)造成錯(cuò)誤的情況比較少,而且他們的效果顯而易見(jiàn),比較容易
            發(fā)現(xiàn)。

            三、怎樣“調(diào)試” Release 版的程序

            ??? 遇到 Debug 成功但 Release 失敗,顯然是一件很沮喪的事,而且往往無(wú)從下手。如
            果你看了以上的分析,結(jié)合錯(cuò)誤的具體表現(xiàn),很快找出了錯(cuò)誤,固然很好。但如果一時(shí)找
            不出,以下給出了一些在這種情況下的策略。

            ??? 1. 前面已經(jīng)提過(guò),Debug 和 Release 只是一組編譯選項(xiàng)的差別,實(shí)際上并沒(méi)有什么
            定義能區(qū)分二者。我們可以修改 Release 版的編譯選項(xiàng)來(lái)縮小錯(cuò)誤范圍。如上所述,可以
            把 Release 的選項(xiàng)逐個(gè)改為與之相對(duì)的 Debug 選項(xiàng),如 /MD 改為 /MDd、/O1 改為 /Od
            ,或運(yùn)行時(shí)間優(yōu)化改為程序大小優(yōu)化。注意,一次只改一個(gè)選項(xiàng),看改哪個(gè)選項(xiàng)時(shí)錯(cuò)誤消
            失,再對(duì)應(yīng)該選項(xiàng)相關(guān)的錯(cuò)誤,針對(duì)性地查找。這些選項(xiàng)在 Project\Settings... 中都可
            以直接通過(guò)列表選取,通常不要手動(dòng)修改。由于以上的分析已相當(dāng)全面,這個(gè)方法是最有
            效的。

            ??? 2. 在編程過(guò)程中就要時(shí)常注意測(cè)試 Release 版本,以免最后代碼太多,時(shí)間又很緊

            ??? 3. 在 Debug 版中使用 /W4 警告級(jí)別,這樣可以從編譯器獲得最大限度的錯(cuò)誤信息,
            比如 if( i =0 )就會(huì)引起 /W4 警告。不要忽略這些警告,通常這是你程序中的 Bug 引起
            的。但有時(shí) /W4 會(huì)帶來(lái)很多冗余信息,如 未使用的函數(shù)參數(shù) 警告,而很多消息處理函數(shù)
            都會(huì)忽略某些參數(shù)。我們可以用
            ????? #progma warning(disable: 4702) //禁止
            ????? //...
            ????? #progma warning(default: 4702) //重新允許
            來(lái)暫時(shí)禁止某個(gè)警告,或使用
            ????? #progma warning(push, 3) //設(shè)置警告級(jí)別為 /W3
            ????? //...
            ????? #progma warning(pop) //重設(shè)為 /W4
            來(lái)暫時(shí)改變警告級(jí)別,有時(shí)你可以只在認(rèn)為可疑的那一部分代碼使用 /W4。

            ??? 4.你也可以像 Debug 一樣調(diào)試你的 Release 版,只要加入調(diào)試符號(hào)。在 Project/S
            ettings... 中,選中 Settings for "Win32 Release",選中 C/C++ 標(biāo)簽,Category 選
            ?General,Debug Info 選 Program Database。再在 Link 標(biāo)簽 Project options? 最后
            加上 "/OPT:REF" (引號(hào)不要輸)。這樣調(diào)試器就能使用 pdb 文件中的調(diào)試符號(hào)。但調(diào)試時(shí)
            你會(huì)發(fā)現(xiàn)斷點(diǎn)很難設(shè)置,變量也很難找到——這些都被優(yōu)化過(guò)了。不過(guò)令人慶幸的是,Ca
            ll Stack 窗口仍然工作正常,即使幀指針被優(yōu)化,棧信息(特別是返回地址)仍然能找到
            。這對(duì)定位錯(cuò)誤很有幫助。

            posted @ 2006-12-09 14:28 平凡的天才 閱讀(2320) | 評(píng)論 (1)編輯 收藏

            在C/C++語(yǔ)言中,將一個(gè)組合數(shù)據(jù)類型如結(jié)構(gòu)各個(gè)字段的值復(fù)制到另一個(gè)相同類型的結(jié)構(gòu)中,可以將其對(duì)應(yīng)字段賦值。這種方法對(duì)于各種復(fù)雜的結(jié)構(gòu)如多字段結(jié)構(gòu)、嵌套結(jié)構(gòu),就要寫很多行賦值語(yǔ)句,而且如果原來(lái)的結(jié)構(gòu)定義更改,程序代碼就要隨著更改,使用很不方便。本文給出了一個(gè)通用的結(jié)構(gòu)復(fù)制函數(shù)。
            ????????假定結(jié)構(gòu)的類型為STRUCT_TYPE。為了提高效率,用指針引入兩個(gè)結(jié)構(gòu)到函數(shù)中;為了通用,這兩個(gè)指針用任意指針。函數(shù)設(shè)計(jì)的出發(fā)點(diǎn)是,每個(gè)結(jié)構(gòu)在內(nèi)存中各字段連續(xù)存放,而且,每個(gè)字段可以分解中一個(gè)一個(gè)的字節(jié)。這樣,復(fù)制結(jié)構(gòu)時(shí),可以讓兩個(gè)結(jié)構(gòu)的對(duì)應(yīng)的每個(gè)字節(jié)表示的值相等。于是,函數(shù)設(shè)計(jì)如下:


            ??void?struct_copy(
            ????void?*p_struct1,???/*結(jié)構(gòu)指針1*/
            ????void?*p_struct2,???/*結(jié)構(gòu)指針2*/
            ????unsigned?int?struct_size???/*結(jié)構(gòu)類型長(zhǎng)度,可以用sizeof(STRUCT_TYPE)代入*/
            ?????)
            ????{
            ?int?count=0;
            ?char?*p_char1,*p_char2;
            ?
            ?p_char1=(char?*)p_struct1;
            ?p_char2=(char?*)p_struct2;
            ?
            ?while(count!=struct_size)
            ?{
            ??*p_char1=*p_char2;
            ??p_char1++;
            ??p_char2++;
            ??count++;
            ?}
            ????}
            這個(gè)函數(shù)在PC機(jī)和康柏ALPHA小型機(jī)上使用效果不錯(cuò)。
            ????????有了這個(gè)函數(shù),如有類型同為STRUCT_TYPE的兩個(gè)結(jié)構(gòu)struct1和struct2,要使struct1各字段的值與struct2各字段的值相等,也就是要把struct2各字段的值賦給struct1,就可以這樣調(diào)用以上函數(shù):?struct_copy(&struct1,?&struct2,?sizeof(STRUCT_TYPE));??????
            ????????以上函數(shù)簡(jiǎn)單、通用、有效,對(duì)任意結(jié)構(gòu)類型有效,也適合于其它復(fù)雜數(shù)據(jù)類型,如聯(lián)合(union)等。有趣的是,它也適合與整形、浮點(diǎn)型等簡(jiǎn)單數(shù)據(jù)類型的變量之間復(fù)制。
            ????????此函數(shù)的設(shè)計(jì)思想可以運(yùn)用在很多方面,如進(jìn)程之間、計(jì)算機(jī)之間通信時(shí),可以在通信的一方將某些數(shù)據(jù)類型拆分成字節(jié),到達(dá)通信的另一方再將收到的字節(jié)拼成相應(yīng)的數(shù)據(jù)類型,這比按位傳遞要簡(jiǎn)單、高效得多。

            posted @ 2006-11-29 19:31 平凡的天才 閱讀(1527) | 評(píng)論 (9)編輯 收藏

            SetLayeredWindowAttributes函數(shù):
            hwnd是透明窗體的句柄,
            crKey為顏色值,
            bAlpha是透明度,取值范圍是[0,255],
            dwFlags是透明方式,可以取兩個(gè)值:???????? 當(dāng)取值為L(zhǎng)WA_ALPHA時(shí),crKey參數(shù)無(wú)效,bAlpha參數(shù)有效;???????? 當(dāng)取值為L(zhǎng)WA_COLORKEY時(shí),bAlpha參數(shù)有效而窗體中的所有顏色為crKey的地方將變?yōu)橥该鳌??????? LWA_ALPHA = 0x2??????? LWA_COLORKEY=0x1 要使使窗體擁有透明效果,首先要有WS_EX_LAYERED擴(kuò)展屬性 (舊的sdk沒(méi)有定義這個(gè)屬性,所以可以直接指定為0x80000). WS_EX_LAYERED = 0x80000

            posted @ 2006-11-28 21:48 平凡的天才 閱讀(12044) | 評(píng)論 (2)編輯 收藏

            /*相信這個(gè)算法是天才做出來(lái)的*/
            #include <stdio.h>
            #include <conio.h>


            int main(int argc, char *argv[])
            {
            ?int a[10]={125,26,35,24,548,256,25,298,7852,11},i,max[2];
            ?max[0]=max[1]=-32767;
            ?for(i=0;i<10;i++)
            ?{
            ??if(max[0]<a[i])
            ??{
            ???max[1]=max[0];
            ???max[0]=a[i];
            ??}
            ??else
            ??{
            ???if(max[1]<a[i])
            ???{
            ????max[1]=a[i];
            ???}
            ??}
            ?}
            ?for(i=0;i<10;i++)
            ?{
            ??printf("%d ",a[i]);
            ?}
            ?printf("\n");
            ?printf("max[0]=%d\n",max[0]);
            ?printf("max[1]=%d\n",max[1]);
            ?getch();?
            ?return 0;
            }

            posted @ 2006-11-24 20:15 平凡的天才 閱讀(1886) | 評(píng)論 (9)編輯 收藏

            經(jīng)過(guò)千辛萬(wàn)苦,我終于開(kāi)博客了
            剛來(lái)給個(gè)規(guī)范吧


            VC編程規(guī)范
            1.?基本要求
            1.1?程序結(jié)構(gòu)清析,簡(jiǎn)單易懂,單個(gè)函數(shù)的程序行數(shù)不得超過(guò)100行。
            1.2?打算干什么,要簡(jiǎn)單,直接了當(dāng),代碼精簡(jiǎn),避免垃圾程序。
            1.3?盡量使用標(biāo)準(zhǔn)庫(kù)函數(shù)和公共函數(shù)。
            1.4?不要隨意定義全局變量,盡量使用局部變量。
            1.5?使用括號(hào)以避免二義性。

            2.可讀性要求
            2.1?可讀性第一,效率第二。
            2.2?保持注釋與代碼完全一致。
            2.3?每個(gè)源程序文件,都有文件頭說(shuō)明,說(shuō)明規(guī)格見(jiàn)規(guī)范。
            2.4?每個(gè)函數(shù),都有函數(shù)頭說(shuō)明,說(shuō)明規(guī)格見(jiàn)規(guī)范。
            2.5?主要變量(結(jié)構(gòu)、聯(lián)合、類或?qū)ο螅┒x或引用時(shí),注釋能反映其含義。
            2.7?常量定義(DEFINE)有相應(yīng)說(shuō)明。
            2.8?處理過(guò)程的每個(gè)階段都有相關(guān)注釋說(shuō)明。
            2.9?在典型算法前都有注釋。
            2.10?利用縮進(jìn)來(lái)顯示程序的邏輯結(jié)構(gòu),縮進(jìn)量一致并以Tab鍵為單位,定義Tab為?6個(gè)
            字節(jié)。
            2.11?循環(huán)、分支層次不要超過(guò)五層。
            2.12?注釋可以與語(yǔ)句在同一行,也可以在上行。
            2.13?空行和空白字符也是一種特殊注釋。
            2.14?一目了然的語(yǔ)句不加注釋。
            2.15?注釋的作用范圍可以為:定義、引用、條件分支以及一段代碼。
            2.16?注釋行數(shù)(不包括程序頭和函數(shù)頭說(shuō)明部份)應(yīng)占總行數(shù)的?1/5?到?1/3?。

            3.?結(jié)構(gòu)化要求
            3.1?禁止出現(xiàn)兩條等價(jià)的支路。
            3.2?禁止GOTO語(yǔ)句。
            3.3?用?IF?語(yǔ)句來(lái)強(qiáng)調(diào)只執(zhí)行兩組語(yǔ)句中的一組。禁止?ELSE?GOTO?和?ELSE?RETURN。
            3.4?用?CASE?實(shí)現(xiàn)多路分支。
            3.5?避免從循環(huán)引出多個(gè)出口。
            3.6?函數(shù)只有一個(gè)出口。
            3.7?不使用條件賦值語(yǔ)句。
            3.8?避免不必要的分支。
            3.9?不要輕易用條件分支去替換邏輯表達(dá)式。

            4.?正確性與容錯(cuò)性要求
            4.1?程序首先是正確,其次是優(yōu)美
            4.2?無(wú)法證明你的程序沒(méi)有錯(cuò)誤,因此在編寫完一段程序后,應(yīng)先回頭檢查。
            4.3?改一個(gè)錯(cuò)誤時(shí)可能產(chǎn)生新的錯(cuò)誤,因此在修改前首先考慮對(duì)其它程序的影響。
            4.4?所有變量在調(diào)用前必須被初始化。
            4.5?對(duì)所有的用戶輸入,必須進(jìn)行合法性檢查。
            4.6?不要比較浮點(diǎn)數(shù)的相等,
            如:?10.0?*?0.1?==?1.0?,?不可靠
            4.7?程序與環(huán)境或狀態(tài)發(fā)生關(guān)系時(shí),必須主動(dòng)去處理發(fā)生的意外事件,如文件能否
            邏輯鎖定、打印機(jī)是否聯(lián)機(jī)等。
            4.8?單元測(cè)試也是編程的一部份,提交聯(lián)調(diào)測(cè)試的程序必須通過(guò)單元測(cè)試。

            5.?可重用性要求

            5.1?重復(fù)使用的完成相對(duì)獨(dú)立功能的算法或代碼應(yīng)抽象為公共控件或類。
            5.2?公共控件或類應(yīng)考慮OO思想,減少外界聯(lián)系,考慮獨(dú)立性或封裝性。
            5.3?公共控件或類應(yīng)建立使用模板。

            附:C++?編程規(guī)范,delphi作相應(yīng)的參考

            .1適用范圍

            本標(biāo)準(zhǔn)適用于利用Visul?C++?,Borland?C++進(jìn)行軟件程序開(kāi)發(fā)的人員.。

            .2變量命名

            命名必須具有一定的實(shí)際意義,形式為xAbcFgh,x由變量類型確定,Abc、Fgh表示連續(xù)意
            義字符串,如果連續(xù)意義字符串僅兩個(gè),可都大寫.如OK.

            具體例程:

            BOOL類型?bEnable;
            ch?*?char?chText
            c?*?類對(duì)象?cMain(對(duì)象實(shí)例)
            h?*?Handle(句柄)?hWnd
            i?*?int
            n?*?無(wú)符號(hào)整型
            p?*?指針
            sz,str?*?字符串
            w?WORD
            x,y?坐標(biāo)

            Char或者TCHAR類型?與Windows?API有直接聯(lián)系的用szAppName[10]形式否則用
            FileName[10]形式,單個(gè)字符也可用小寫字母表示;

            Int類型?nCmdShow;
            LONG類型?lParam;
            UINT類型?uNotify;?
            DWORD類型?dwStart;
            PSTR類型?pszTip;
            LPSTR類型?lpCmdLine
            LPTSTR類型?lpszClassName;
            LPVOID類型?lpReserved
            WPARAM類型?wParam,
            LPARAM類型?lParam
            HWND類型?hDlg;
            HDC類型?hDC;
            HINSTANCE類型?hInstance
            HANDLE類型?hInstance,
            HICON類型?hIcon;
            int?iTmp
            float?fTmp
            DWORD?dw*
            String?,?AnsiString?str?*
            m_?類成員變量?m_nVal,?m_bFlag
            g_?全局變量?g_nMsg,?g_bFlag

            局部變量中可采用如下幾個(gè)通用變量:nTemp,nResult,I,J(一般用于循環(huán)變量)。
            其他資源句柄同上

            .3常量命名和宏定義
            常量和宏定義必須具有一定的實(shí)際意義;
            常量和宏定義在#include和函數(shù)定義之間;
            常量和宏定義必須全部以大寫字母來(lái)撰寫,中間可根據(jù)意義的連續(xù)性用下劃線連接,每一
            條定義的右側(cè)必須有一簡(jiǎn)單的注釋,說(shuō)明其作用;
            資源名字定義格式:
            菜單:IDM_XX或者CM_XX
            位圖:IDB_XX
            對(duì)話框:IDD_XX
            字符串:IDS_XX
            DLGINIT:DIALOG_XX
            ICON:IDR_XX

            .4函數(shù)命名
            函數(shù)原型說(shuō)明包括引用外來(lái)函數(shù)及內(nèi)部函數(shù),外部引用必須在右側(cè)注明函數(shù)來(lái)源:?模
            塊名及文件名,?如是內(nèi)部函數(shù),只要注釋其定義文件名;
            第一個(gè)字母必須使用大寫字母,要求用大小寫字母組合規(guī)范函數(shù)命名,必要時(shí)可用下劃線
            間隔,示例如下:
            void?UpdateDB_Tfgd?(TRACK_NAME);?//Module?Name?:r01/sdw.c
            void?PrintTrackData?(TRACK_NAME);?//Module?Name?:r04/tern.c
            void?ImportantPoint?(void);?//Module?Name?:r01/sdw.c
            void?ShowChar?(int?,?int?,?chtype);?//Local?Module
            void?ScrollUp_V?(int?,?int);?//Local?Module
            .5結(jié)構(gòu)體命名
            結(jié)構(gòu)體類型命名必須全部用大寫字母,原則上前面以下劃線開(kāi)始;結(jié)構(gòu)體變量命名必須用
            大小寫字母組合,第一個(gè)字母必須使用大寫字母,必要時(shí)可用下劃線間隔。對(duì)于私有數(shù)
            據(jù)區(qū),必須注明其所屬的進(jìn)程。全局?jǐn)?shù)據(jù)定義只需注意其用途。

            示例如下:
            typedef?struct
            {
            char?szProductName[20];
            char?szAuthor[20];
            char?szReleaseDate[16];
            char?szVersion[10];?
            unsigned?long?MaxTables;
            unsigned?long?UsedTables;
            }DBS_DATABASE;
            DBS_DATABASE?GdataBase;

            6?控件的命名:
            用小寫前綴表示類別
            用小寫前綴表示類別:
            fm?窗口
            cmd?按鈕
            cob?combo,下拉式列表框
            txt?文本輸入框
            lab?labal,標(biāo)簽
            img?image,圖象
            pic?picture
            grd?Grid,網(wǎng)格
            scr?滾動(dòng)條
            lst?列表框
            frm?fram

            7注釋
            原則上注釋要求使用中文;
            文件開(kāi)始注釋內(nèi)容包括:公司名稱、版權(quán)、作者名稱、時(shí)間、模塊用途、背景介紹等,復(fù)
            雜的算法需要加上流程說(shuō)明;
            函數(shù)注釋包括:輸入、輸出、函數(shù)描述、流程處理、全局變量、調(diào)用樣例等,復(fù)雜的函數(shù)
            需要加上變量用途說(shuō)明;
            程序中注釋包括:修改時(shí)間和作者、方便理解的注釋等;
            引用一:?文件開(kāi)頭的注釋模板
            /******************************************************************

            **?文件名:
            **?Copyright?(c)?1998-1999?*********公司技術(shù)開(kāi)發(fā)部
            **?創(chuàng)建人:
            **?日?期:
            **?修改人:
            **?日?期:
            **?描?述:
            **
            **?版?本:
            **--------------------------------------------------------------------------
            ---
            ******************************************************************/
            引用二:?函數(shù)開(kāi)頭的注釋模板
            /*****************************************************************

            **?函數(shù)名:
            **?輸?入:?a,b,c
            **?a---
            **?b---
            **?c---
            **?輸?出:?x---
            **?x?為?1,?表示...
            **?x?為?0,?表示...
            **?功能描述:
            **?全局變量:
            **?調(diào)用模塊:
            **?作?者:
            **?日?期:
            **?修?改:
            **?日?期:
            **?版本
            ****************************************************************/
            引用三:?程序中的注釋模板
            /*----------------------------------------------------------*/
            /*?注釋內(nèi)容?*/
            /*----------------------------------------------------------*/
            8?程序
            a.?程序編碼力求簡(jiǎn)潔,結(jié)構(gòu)清晰,避免太多的分支結(jié)構(gòu)及太過(guò)于技巧性的程序,
            盡量不采用遞歸模式。
            b.?編寫程序時(shí),亦必須想好測(cè)試的方法,換句話說(shuō),”單元測(cè)試”?的測(cè)試方案應(yīng)
            在程序編寫時(shí)一并擬好。
            c.?注釋一定要與程序一致。
            d.?版本封存以后的修改一定要將老語(yǔ)句用/*?*/?封閉,不能自行刪除或修改,并要
            在文件及函數(shù)的修改記錄中加以記錄。
            e.?程序中每個(gè)block?的開(kāi)頭?”{"?及?"}”?必須對(duì)齊,嵌套的block?每進(jìn)一套,
            縮進(jìn)一個(gè)tab,TAB?為4個(gè)空格,block類型包括if、for、while、do等關(guān)鍵字引出的。
            f.?對(duì)于比較大的函數(shù),每個(gè)block?和特殊的函數(shù)調(diào)用,都必須注明其功能,舉例如下

            count.divisor?=?1193280?/?freq;?//?compute?the?proper?count
            OutByte((unsigned?short)67,?(unsigned?char)182);?//?tell?8253?that?a
            count?is?coming
            OutByte((unsigned?short)66,?count.?c[0]);?//?send?low-order?byte
            OutByte((unsigned?short)66,?count.?c[1]);?//?send?high-order?byte
            ×××××××××××××××××××××××××××××××××××××××

            bcb,delphi中的變量命名:
            遵循匈牙利命名法,命
            名必須有意義,制定如下規(guī)定
            窗體:?以大寫的W開(kāi)始,如About版權(quán)窗體,?命名為WAbout
            文件:以大寫的F開(kāi)始,如About版權(quán)窗體,文件命名為FAbout.cpp
            按鈕(Button):如退出按鈕,命名為btnExit

            基類:?加base標(biāo)記,如報(bào)表基類,窗體命名為:WBaseRep,?文件命名為FBaseRep.cpp?

            posted @ 2006-11-24 17:52 平凡的天才 閱讀(2231) | 評(píng)論 (2)編輯 收藏

            僅列出標(biāo)題
            共2頁(yè): 1 2 
            久久精品免费网站网| 久久精品免费全国观看国产| 一级a性色生活片久久无| 99国产精品久久| 九九精品99久久久香蕉| 少妇内射兰兰久久| 中文字幕久久久久人妻| 久久亚洲国产成人影院| 思思久久精品在热线热| 无码人妻久久一区二区三区蜜桃| 欧美亚洲国产精品久久| 久久久SS麻豆欧美国产日韩| 久久成人国产精品免费软件| 久久久久亚洲AV无码专区首JN| 国内精品久久久久久久久电影网| 亚洲国产精品一区二区久久hs| 久久夜色精品国产噜噜噜亚洲AV| 伊人久久大香线蕉av一区| 亚洲精品国产美女久久久| 大伊人青草狠狠久久| 久久青草国产手机看片福利盒子| 久久精品国产99国产精偷| 国产成人综合久久久久久| 日韩亚洲国产综合久久久| 色妞色综合久久夜夜| 久久婷婷激情综合色综合俺也去| 久久ZYZ资源站无码中文动漫 | 久久国产精品免费| 一本大道久久香蕉成人网| 久久久久无码精品国产不卡| 久久这里只有精品久久| 色诱久久av| 久久久久久久综合日本亚洲| 无码乱码观看精品久久| 乱亲女H秽乱长久久久| 久久久精品免费国产四虎| 无码任你躁久久久久久久| 久久99国产综合精品女同| 久久久久亚洲AV无码去区首| 香蕉久久av一区二区三区| 国产精品xxxx国产喷水亚洲国产精品无码久久一区 |