• <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 - 149,comments - 125,trackbacks - 0

            摘自:http://www.diybl.com/course/3_program/c++/cppjs/2008426/111619.html
              
                  去年11月的MSDN雜志曾刊登過一篇文章 Break Free of Code Deadlocks in Critical Sections Under Windows ,Matt Pietrek 和 Russ Osterlund 兩位對臨界區(Critical Section)的內部實現做了一次簡短的介紹,但點到為止,沒有繼續深入下去,當時給我的感覺就是癢癢的,呵呵,于是用IDA和SoftIce大致分析了一下臨界區的實現,大致弄明白了原理后也就沒有深究?,F在乘著Win2k源碼的東風,重新分析一下這塊的內容,做個小小的總結吧 :P
                 臨界區(Critical Section)是Win32中提供的一種輕量級的同步機制,與互斥(Mutex)和事件(Event)等內核同步對象相比,臨界區是完全在用戶態維護的,所以僅能在同一進程內供線程同步使用,但也因此無需在使用時進行用戶態和核心態之間的切換,工作效率大大高于其它同步機制。
                 臨界區的使用方法非常簡單,使用 InitializeCriticalSection 或 InitializeCriticalSectionAndSpinCount 函數初始化一個 CRITICAL_SECTION 結構;使用 SetCriticalSectionSpinCount 函數設置臨界區的Spin計數器;然后使用 EnterCriticalSection 或 TryEnterCriticalSection 獲取臨界區的所有權;完成需要同步的操作后,使用 LeaveCriticalSection 函數釋放臨界區;最后使用 DeleteCriticalSection 函數析構臨界區結構。
                 以下是MSDN中提供的一個簡單的例子:

                以下為引用:

             // Global variable
             CRITICAL_SECTION CriticalSection;

             void main()
             {
                 ...

                 // Initialize the critical section one time only.
                 if (!InitializeCriticalSectionAndSpinCount(&CriticalSection, 0x80000400) )
                     return;
                 ...

                 // Release resources used by the critical section object.
                 DeleteCriticalSection(&CriticalSection)
             }

             DWORD WINAPI ThreadProc( LPVOID lpParameter )
             {
                 ...

                 // Request ownership of the critical section.
                 EnterCriticalSection(&CriticalSection);

                 // Access the shared resource.

                 // Release ownership of the critical section.
                 LeaveCriticalSection(&CriticalSection);

                 ...
             }

                 首先看看構造和析構臨界區結構的函數。
                 InitializeCriticalSection 函數(ntosdll esource.c:1210)實際上是調用 InitializeCriticalSectionAndSpinCount 函數(resource.c:1266)完成功能的,只不過傳入一個值為0的初始Spin計數器;InitializeCriticalSectionAndSpinCount 函數主要完成兩部分工作:初始化 RTL_CRITICAL_SECTION 結構和 RTL_CRITICAL_SECTION_DEBUG 結構。前者是臨界區的核心結構,下面將著重討論;后者是調試用結構,Matt 那篇文章里面分析的很清楚了,我這兒就不羅嗦了 :P
                 RTL_CRITICAL_SECTION結構在winnt.h中定義如下:

            以下為引用:

             typedef struct _RTL_CRITICAL_SECTION {
                 PRTL_CRITICAL_SECTION_DEBUG DebugInfo;

                 //
                 //  The following three fields control entering and exiting the critical
                 //  section for the resource
                 //

                 LONG LockCount;
                 LONG RecursionCount;
                 HANDLE OwningThread;        // from the thread''s

            ClientId->UniqueThread
                 HANDLE LockSemaphore;
                 ULONG_PTR SpinCount;        // force size on 64-bit systems when packed
             } RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;

                 InitializeCriticalSectionAndSpinCount 函數中首先對臨界區結構進行了初始化

                 DebugInfo 字段指向初始化臨界區時分配的RTL_CRITICAL_SECTION_DEBUG結構;
                 LockCount 字段是臨界區中最重要的字段,初始值為-1,當臨界區被獲取(Hold)時此字段大于等于0;
                 RecursionCount 字段保存當前臨界區所有者線程的獲取緩沖區嵌套層數,初始值為0;
                 OwningThread 字段保存當前臨界區所有者線程的句柄,初始值為0;
                 LockSemaphore 字段實際上是一個auto-reset的事件句柄,用于喚醒等待獲取臨界區的阻塞線程,初始值為0;
                 SpinCount 字段用于在多處理器環境下完成輕量級的CPU見同步,單處理器時沒有使用(初始值為0),多處理器時設置為SpinCount參數值(最大為MAX_SPIN_COUNT=0x00ffffff)。此外 RtlSetCriticalSectionSpinCount 函數(resource.c:1374)的代碼與這兒設置SpinCount的代碼完全一樣。

                 初始化臨界區結構后,函數會根據SpinCount參數的一個標志位判斷是否需要預先初始化 LockSemaphore 字段,如果需要則使用NtCreateEvent創建一個具有訪問權限的同步用事件核心對象,初始狀態為沒有激發。這一初始化本來是在 EnterCriticalSection 函數中完成的,將之顯式提前可以進一步優化 EnterCriticalSection 函數的性能。
                 值得注意的是,這一特性僅對Win2k有效。MSDN里面說明如下:

            以下為引用:

             Windows 2000:  If the high-order bit is set, the function preallocates the event used by the EnterCriticalSection function. Do not set this bit if you are creating a large number of critical section objects, because it will consume a significant amount of nonpaged pool. This flag is not necessary on Windows XP and later, and it is ignored.

                 與之對應的 DeleteCriticalSection 函數完成關閉事件句柄和是否調試結構的功能。

                 臨界區真正的核心代碼在win2kprivate tosdlli386critsect.asm里面,包括_RtlEnterCriticalSection、_RtlTryEnterCriticalSection和_RtlLeaveCriticalSection三個函數。

                 _RtlEnterCriticalSection 函數 (critsect.asm:85) 首先檢查SpinCount是否為0,如果不為0則處理多處理器架構下的問題[分支1];如為0則使用原子操作給LockCount加一,并判斷是否其值為0。如果加一后LockCount大于0,則此臨界區已經被獲取[分支2];如為0則獲取當前線程TEB中的線程句柄,保存在臨界區的OwningThread字段中,并將RecursionCount設置為1。調試版本則調用RtlpCriticalSectionIsOwned函數在調試模式下驗證此緩沖區是被當前線程獲取的,否則在調試模式下激活調試器。最后還會更新TEB的CountOfOwnedCriticalSections計數器,以及臨界區調試結構中的EntryCount字段。
                 如果此臨界區已經被獲取[分支2],則判斷獲取臨界區的線程句柄是否與當前線程相符。如果是同一線程則直接將RecursionCount和調試結構的EntryCount字段加一;如果不是當前線程,則調用RtlpWaitForCriticalSection函數等待此臨界區,并從頭開始執行獲取臨界區的程序。
                 多CPU情況的分支處理方式類似,只是多了對SpinCount的雙重檢查處理。

                 接著的_RtlTryEnterCriticalSection(critsect.asm:343)函數是一個輕量級的嘗試獲取臨界區的函數。偽代碼如下:

            以下為引用:

             if(CriticalSection->LockCount == -1)
             {
               // 臨界區可用
               CriticalSection->LockCount = 0;
               CriticalSection->OwningThread = TEB->ClientID;
               CriticalSection->RecursionCount = 1;

               return TRUE;
             }
             else
             {
               if(CriticalSection->OwningThread == TEB->ClientID)
               {
                 // 臨界區是當前線程獲取
                 CriticalSection->LockCount++;
                 CriticalSection->RecursionCount++;

                 return TRUE;
               }
               else
               {
                 // 臨界區已被其它線程獲取
                 return FALSE;
               }
             }
             
             

             

             

                 最后的_RtlLeaveCriticalSection(critsect.asm:271)函數釋放已獲取的臨界區,實現就比較簡單了,實際上就是對嵌套計數器和鎖定計數器進行操作。偽代碼如下:

             

            以下為引用:

             if(--CriticalSection->RecursionCount == 0)
             {
            bsp;  // 臨界區已不再被使用
               CriticalSection->OwningThread = 0;
             

               if(--CriticalSection->LockCount)
               {
                 // 仍有線程鎖定在臨界區上
                 _RtlpUnWaitCriticalSection(CriticalSection)
               }
             }
             else
             {
               --CriticalSection->LockCount
             }

            posted @ 2008-12-01 14:05 Sandy 閱讀(1814) | 評論 (0)編輯 收藏
            一、宏中“#”和“##”的用法:

                    一般用法:使用“#”把宏參數變為一個字符串,用”##”把兩個宏參數結合在一起

                   例子:

            #include <iostream>
            using namespace std;

            #define TEST1(x) (cout<<id##x<<endl);
            #define TEST2(p) (cout<<#p<<endl);
            int main()
            {
                
            int id1 = 1001;
                
            int id2 = 1002;
                TEST1(
            1);    // == cout<< id1 << endl;
                TEST2(2);    // == cout<< "2" << endl;
                TEST1(2);    // == cout<< id2 << endl;

                system(
            "pause");
                
            return 0;
            }

            二、防止一個頭文件被重復包含
                    #ifndef COMDEF_H
                    #define COMDEF_H
                    //頭文件內容
                    #endif
                當你所建的工程有多個源文件組成時,很可能會在多個文件里頭包含了同一個頭文件,如果借用上面的宏定義就能夠避免同一個頭文件被重復包含時進行多次編譯。因為當它編譯第一個頭文件時總是沒有定義#define COMDEF_H,那么它將編譯一遍頭文件中所有的內容,包括定義#define COMDEF_H。這樣編譯再往下進行時如果遇到同樣要編譯的頭文件,那么由于語句#ifndef COMDEF_H的存在它將不再重復的編譯這個頭文件。

            三、常用的宏定義
              __DATE__
              進行預處理的日期(“Mmm dd yyyy”形式的字符串文字)

              __FILE__
              代表當前源代碼文件名的字符串文字

              __LINE__
              代表當前源代碼中的行號的整數常量

              __TIME__
              源文件編譯時間,格式微“hh:mm:ss”

            參考文章:
               C中的預編譯宏定義  http://blog.readnovel.com/article/htm/tid_900939.html
               C標準中一些預定義的宏 http://www.programfan.com/article/2883.html
               C語言常用宏定義技巧  http://blog.21ic.com/user1/3074/archives/2008/51567.html
               C語言宏定義技巧(常用宏定義) http://blog.21ic.com/user1/69/archives/2006/13695.html
               宏定義:http://blog.csdn.net/believefym/archive/2007/10/21/1836162.aspx

            好好學習!
             
            posted @ 2008-12-01 13:54 Sandy 閱讀(1882) | 評論 (0)編輯 收藏
            好文章,大家一起分享。

            一直對extern "c"不是很明白。今天,看了一篇文章《C++中extern “C”含義深層探索》,對這個問題終于有所認識。轉過來與大家分享。

            鏈接:http://developer.51cto.com/art/200510/9066.htm
            作者:宋寶華

            1.引言
            C++語言的創建初衷是“a better C”,但是這并不意味著C++中類似C語言的全局變量和函數所采用的編譯和連接方式與C語言完全相同。作為一種欲與C兼容的語言,C++保留了一部分過程式語言的特點(被世人稱為“不徹底地面向對象”),因而它可以定義不屬于任何類的全局變量和函數。但是,C++畢竟是一種面向對象的程序設計語言,為了支持函數的重載,C++對全局函數的處理方式與C有明顯的不同。
            2.從標準頭文件說起

            某企業曾經給出如下的一道面試題:
            面試題:為什么標準頭文件都有類似以下的結構?
            #ifndef __INCvxWorksh
            #define __INCvxWorksh
            #ifdef __cplusplus
            extern "C" {
            #endif
            /*...*/
            #ifdef __cplusplus
            }
            #endif
            #endif /* __INCvxWorksh */
            分析
            顯然,頭文件中的編譯宏“#ifndef __INCvxWorksh、#define __INCvxWorksh、#endif” 的作用是防止該頭文件被重復引用。
            那么
            #ifdef __cplusplus
            extern "C" {
            #endif
            #ifdef __cplusplus
            }
            #endif
            的作用又是什么呢?我們將在下文一一道來。

            3.深層揭密extern "C"

            extern "C" 包含雙重含義,從字面上即可得到:首先,被它修飾的目標是“extern”的;其次,被它修飾的目標是“C”的。讓我們來詳細解讀這兩重含義。
            被extern "C"限定的函數或變量是extern類型的;
            extern是C/C++語言中表明函數和全局變量作用范圍(可見性)的關鍵字,該關鍵字告訴編譯器,其聲明的函數和變量可以在本模塊或其它模塊中使用。記住,下列語句:
            extern int a;
            僅僅是一個變量的聲明,其并不是在定義變量a,并未為a分配內存空間。變量a在所有模塊中作為一種全局變量只能被定義一次,否則會出現連接錯誤。
            通常,在模塊的頭文件中對本模塊提供給其它模塊引用的函數和全局變量以關鍵字extern聲明。例如,如果模塊B欲引用該模塊A中定義的全局變量和函數時只需包含模塊A的頭文件即可。這樣,模塊B中調用模塊A中的函數時,在編譯階段,模塊B雖然找不到該函數,但是并不會報錯;它會在連接階段中從模塊A編譯生成的目標代碼中找到此函數。
            與extern對應的關鍵字是static,被它修飾的全局變量和函數只能在本模塊中使用。因此,一個函數或變量只可能被本模塊使用時,其不可能被extern “C”修飾。
            被extern "C"修飾的變量和函數是按照C語言方式編譯和連接的;
            未加extern “C”聲明時的編譯方式
            首先看看C++中對類似C的函數是怎樣編譯的。
            作為一種面向對象的語言,C++支持函數重載,而過程式語言C則不支持。函數被C++編譯后在符號庫中的名字與C語言的不同。例如,假設某個函數的原型為:
            void foo( int x, int y );
            該函數被C編譯器編譯后在符號庫中的名字為_foo,而C++編譯器則會產生像_foo_int_int之類的名字(不同的編譯器可能生成的名字不同,但是都采用了相同的機制,生成的新名字稱為“mangled name”)。
            foo_int_int這樣的名字包含了函數名、函數參數數量及類型信息,C++就是靠這種機制來實現函數重載的。例如,在C++中,函數void foo( int x, int y )與void foo( int x, float y )編譯生成的符號是不相同的,后者為_foo_int_float。

            同樣地,C++中的變量除支持局部變量外,還支持類成員變量和全局變量。用戶所編寫程序的類成員變量可能與全局變量同名,我們以"."來區分。而本質上,編譯器在進行編譯時,與函數的處理相似,也為類中的變量取了一個獨一無二的名字,這個名字與用戶程序中同名的全局變量名字不同。
            未加extern "C"聲明時的連接方式
            假設在C++中,模塊A的頭文件如下:
            // 模塊A頭文件 moduleA.h
            #ifndef MODULE_A_H
            #define MODULE_A_H
            int foo( int x, int y );
            #endif
            在模塊B中引用該函數:
            // 模塊B實現文件 moduleB.cpp
            #include "moduleA.h"
            foo(2,3);

            實際上,在連接階段,連接器會從模塊A生成的目標文件moduleA.obj中尋找_foo_int_int這樣的符號!
            加extern "C"聲明后的編譯和連接方式
            加extern "C"聲明后,模塊A的頭文件變為:
            // 模塊A頭文件 moduleA.h
            #ifndef MODULE_A_H
            #define MODULE_A_H
            extern "C" int foo( int x, int y );
            #endif
            在模塊B的實現文件中仍然調用foo( 2,3 ),其結果是:
            (1)模塊A編譯生成foo的目標代碼時,沒有對其名字進行特殊處理,采用了C語言的方式;
            (2)連接器在為模塊B的目標代碼尋找foo(2,3)調用時,尋找的是未經修改的符號名_foo。
            如果在模塊A中函數聲明了foo為extern "C"類型,而模塊B中包含的是extern int foo( int x, int y ) ,則模塊B找不到模塊A中的函數;反之亦然。
            所以,可以用一句話概括extern “C”這個聲明的真實目的(任何語言中的任何語法特性的誕生都不是隨意而為的,來源于真實世界的需求驅動。我們在思考問題時,不能只停留在這個語言是怎么做的,還要問一問它為什么要這么做,動機是什么,這樣我們可以更深入地理解許多問題):
            實現C++與C及其它語言的混合編程。

            明白了C++中extern "C"的設立動機,我們下面來具體分析extern "C"通常的使用技巧。

            4.extern "C"的慣用法
            (1)在C++中引用C語言中的函數和變量,在包含C語言頭文件(假設為cExample.h)時,需進行下列處理:
            extern "C"
            {
            #include "cExample.h"
            }
            而在C語言的頭文件中,對其外部函數只能指定為extern類型,C語言中不支持extern "C"聲明,在.c文件中包含了extern "C"時會出現編譯語法錯誤。
            筆者編寫的C++引用C函數例子工程中包含的三個文件的源代碼如下:
            /* c語言頭文件:cExample.h */
            #ifndef C_EXAMPLE_H
            #define C_EXAMPLE_H
            extern int add(int x,int y);
            #endif
            /* c語言實現文件:cExample.c */
            #include "cExample.h"
            int add( int x, int y )
            {
            return x + y;
            }
            // c++實現文件,調用add:cppFile.cpp
            extern "C"
            {
            #include "cExample.h"
            }
            int main(int argc, char* argv[])
            {
            add(2,3);
            return 0;
            }
            如果C++調用一個C語言編寫的.DLL時,當包括.DLL的頭文件或聲明接口函數時,應加extern "C" { }。
            (2)在C中引用C++語言中的函數和變量時,C++的頭文件需添加extern "C",但是在C語言中不能直接引用聲明了extern "C"的該頭文件,應該僅將C文件中將C++中定義的extern "C"函數聲明為extern類型。

            筆者編寫的C引用C++函數例子工程中包含的三個文件的源代碼如下:
            //C++頭文件 cppExample.h
            #ifndef CPP_EXAMPLE_H
            #define CPP_EXAMPLE_H
            extern "C" int add( int x, int y );
            #endif
            //C++實現文件 cppExample.cpp
            #include "cppExample.h"
            int add( int x, int y )
            {
            return x + y;
            }
            /* C實現文件 cFile.c
            /* 這樣會編譯出錯:#include "cExample.h" */
            extern int add( int x, int y );
            int main( int argc, char* argv[] )
            {
            add( 2, 3 );
            return 0;
            }
            如果深入理解了第3節中所闡述的extern "C"在編譯和連接階段發揮的作用,就能真正理解本節所闡述的從C++引用C函數和C引用C++函數的慣用法。

            posted @ 2008-12-01 11:43 Sandy 閱讀(326) | 評論 (0)編輯 收藏
              MUI,其英文全拼為:Multilingual User Interface。這幾天思考如何運用多語言的問題,查到了一些相關資料,貼出來與大家分享。
               
               Multilingual User Interface (MUI) 
               http://msdn.microsoft.com/en-us/library/aa913592.aspx
               The Multilingual User Interface (MUI) allows users to change the language of the user interface (UI). To make this possible, the MUI uses a single core binary that includes the system default language, together with one resource dynamic-link library (DLL) for each additional target language. The target device boots with the system default language and then a new user-selected language goes into effect after a soft reset. This switch requires recreating windows, menus, and dialog boxes with the newly loaded resources. In addition, to be considered successful, the language switch must display these elements with the correct fonts and with the correct locale-specific information. 
               
               In  This Section
               For All Platforms: 
               Multilingual User Interface (MUI) Application Development
               Provides an overview of the MUI architecture. Provides instructions on how to work with fonts in a multilingual user-interface environment and shows how to use MUI with applications. 
               Multilingual User Interface (MUI) Reference
               Provides reference pages for the MUI application programming interface.
                For Windows Embedded CE: 
                Multilingual User Interface (MUI) OS Design Development
                Provides information about the MUI support that is helpful when designing and developing a Windows Embedded CE OS. This includes dependency information, the modules and components that implement MUI, and MUI implementation considerations. 
                How to Create a Multilingual Run-time Image Using MUI
                Demonstrates how to create a run-time image in both French and English by using MUI.
                Multilingual User Interface (MUI) Registry Settings
                Provides registry-related information for MUI.
                Multilingual User Interface (MUI) Migration
                Provides information about factors to consider when migrating to a newer version of Windows Embedded CE

            posted @ 2008-11-23 11:07 Sandy 閱讀(2052) | 評論 (0)編輯 收藏
                    
                  總在快樂的時候,感到微微的惶恐
                 在開懷大笑時,留下感動的淚水
                 我無法相信單純的幸福
                 對人生的起伏悲苦,既坦然又不安
                                           ————摘自幾米漫畫

                    摘了這么幾句與大家分享。心情煩惱得時候,會看看漫畫,緩解一些心情。如果你也有心煩意亂的時候,看看漫畫,或者看看喜劇,開懷的一笑,讓你從你煩惱中脫離。
                    最近心情也相當壓抑,甚至萬分郁悶。周末了,看到這么幾句,心有所感,與大家分享。
            posted @ 2008-11-22 00:24 Sandy 閱讀(574) | 評論 (0)編輯 收藏
            如何添加代碼注釋?
            這個我一直沒有搞懂。自己隨便涂鴉,也懶得加注釋。但是真正參加項目,有時也會找理由不添注釋。看了一些書,參加一些培訓,有的人說,加注釋好,有人說加注釋不好。好有好的地方,壞也有壞的味道。對于我這個初來乍到之人來說,反而倒是非常迷惑。
            最近看到一篇文章“添加代碼注釋13個技巧”,也解除了心中的部分疑團。貼在這里與大家分享,也備以后參考。
            鏈接:
            http://sunxinhe.yo2.cn/articles/%E3%80%90%E8%BD%AC%E3%80%91%E6%B7%BB%E5%8A%A0%E4%BB%A3%E7%A0%81%E6%B3%A8%E9%87%8A13%E4%B8%AA%E6%8A%80%E5%B7%A7.html

            添加代碼注釋13個技巧

            作者:José M. Aguilar(西班牙語)
            英文譯者:Timm Martin
            中文譯者:numenzq

            下面的13個技巧向你展示如何添加代碼注釋,這些技巧都很容易理解和記憶。

            1. 逐層注釋
            為每個代碼塊添加注釋,并在每一層使用統一的注釋方法和風格。例如:
            針對每個類:包括摘要信息、作者信息、以及最近修改日期等
            針對每個方法:包括用途、功能、參數和返回值等
            在團隊工作中,采用標準化的注釋尤為重要。當然,使用注釋規范和工具(例如C#里的XML,Java里的Javadoc)可以更好的推動注釋工作完成得更好。
            2. 使用分段注釋
            如果有多個代碼塊,而每個代碼塊完成一個單一任務,則在每個代碼塊前添加一個注釋來向讀者說明這段代碼的功能。例子如下:

            // Check that all data records
            // are correct
            foreach (Record record in records)
            {
            if (rec.checkStatus()==Status.OK)
            {
            . . .
            }
            }
            // Now we begin to perform
            // transactions
            Context ctx = new ApplicationContext();
            ctx.BeginTransaction();
            . . .

            3. 在代碼行后添加注釋
            如果多行代碼的每行都要添加注釋,則在每行代碼后添加該行的注釋,這將很容易理解。例如:

            const MAX_ITEMS = 10; // maximum number of packets
            const MASK = 0x1F;    // mask bit TCP

            在分隔代碼和注釋時,有的開發者使用tab鍵,而另一些則使用空格鍵。然而由于tab鍵在各編輯器和IDE工具之間的表現不一致,因此最好的方法還是使用空格鍵。

            4. 不要侮辱讀者的智慧

            避免以下顯而易見的注釋:

            if (a == 5)      // if a equals 5
            counter = 0; // set the counter to zero

            寫這些無用的注釋會浪費你的時間,并將轉移讀者對該代碼細節的理解。

            5. 禮貌點
            避免粗魯的注釋,如:“注意,愚蠢的使用者才會輸入一個負數”或“剛修復的這個問題出于最初的無能開發者之手”。這樣的注釋能夠反映到它的作者是多么的拙劣,你也永遠不知道誰將會閱讀這些注釋,可能是:你的老板,客戶,或者是你剛才侮辱過的無能開發者。

            6. 關注要點

            不要寫過多的需要轉意且不易理解的注釋。避免ASCII藝術,搞笑,詩情畫意,hyperverbosity的注釋。簡而言之,保持注釋簡單直接。

            7. 使用一致的注釋風格
            一些人堅信注釋應該寫到能被非編程者理解的程度。而其他的人則認為注釋只要能 被開發人員理解就行了。無論如何,Successful Strategies for Commenting Code已經規定和闡述了注釋的一致性和針對的讀者。就個人而言,我懷疑大部分非編程人員將會去閱讀代碼,因此注釋應該是針對其他的開發者而言。

            8. 使用特有的標簽
            在一個團隊工作中工作時,為了便于與其它程序員溝通,應該采用一致的標簽集進行注釋。例如,在很多團隊中用TODO標簽表示該代碼段還需要額外的工作。

            int Estimate(int x, int y)
            {
            // TODO: implement the calculations
            return 0;
            }

            注釋標簽切忌不要用于解釋代碼,它只是引起注意或傳遞信息。如果你使用這個技巧,記得追蹤并確認這些信息所表示的是什么。

            9. 在代碼時添加注釋
            在寫代碼時就添加注釋,這時在你腦海里的是清晰完整的思路。如果在代碼最后再添 加同樣注釋,它將多花費你一倍的時間。而“我沒有時間寫注釋”,“我很忙”和“項目已經延期了”這都是不愿寫注釋而找的借口。一些開發者覺得應該 write comments before code,用于理清頭緒。例如:
            public void ProcessOrder()
            {
            // Make sure the products are available
            // Check that the customer is valid
            // Send the order to the store
            // Generate bill
            }

            10. 為自己注釋代碼

            當注釋代碼時,要考慮到不僅將來維護你代碼的開發人員要看,而且你自己也可能要看。用Phil Haack大師的話來說就是:“一旦一行代碼顯示屏幕上,你也就成了這段代碼的維護者”。因此,對于我們寫得好(差)的注釋而言,我們將是第一個受益者(受害者)。

            11. 同時更新代碼和注釋

            如果注釋沒有跟隨代碼的變化而變化,及時是正確的注釋也沒有用。代碼和注釋應該同步變化,否則這樣的注釋將對維護你代碼的開發者帶來更大的困難。使用重構工具時應特別注意,它只會自動更新代碼而不會修改注釋,因此應該立即停止使用重構工具。

            12. 注釋的黃金規則:易讀的代碼
            對于開發者的一個基本原則就是:讓你的代碼為己解釋。雖然有些人懷疑這會讓那些不愿意寫注釋的開發者鉆空子,不過這樣的代碼真的會使你容易理解,還不需要額外維護注釋。例如在Fluid Interfaces文章里向你展示的代碼一樣:

            Calculator calc = new Calculator();
            calc.Set(0);
            calc.Add(10);
            calc.Multiply(2);
            calc.Subtract(4);
            Console.WriteLine( "Result: {0}", calc.Get() );

            在這個例子中,注釋是不需要的,否則可能就違反了技巧4。為了使代碼更容易理解,你可以考慮使用適當的名字 (Ottinger's Rules里講解得相當好),確保正確的縮進,并且采用coding style guides,違背這個技巧可能的結果就像是注釋在為不好的代碼apologize。

            13. 與同事分享技巧
            雖然技巧10已經向我們表明了我們是如何從好的注釋中直接受益,這些技巧將讓所有開發者受益,特別是團隊中一起工作的同事。因此,為了編寫出更容易理解和維護的代碼,嘗試自由的和你的同事分享這些注釋技巧。


            好東西拿出來一起分享
            posted @ 2008-11-20 09:38 Sandy 閱讀(1113) | 評論 (1)編輯 收藏

            今天突然遇到Active Sync 4.5 setup.msi這個工具在windows vista系統上裝不上這個問題,查了一下,原來在windows vista上,不再采用Active Sync ,而是采用了drvupdate-x86.exe,具體名字叫做Microsoft Windows Mobile 設備中心6.1。微軟對其的描述是:
            使用 Windows Mobile 設備中心,您可以建立新的合作關系,與 Windows Mobile 設備(Windows Mobile 2003 或更高版本)同步音樂、圖片和視頻,并對其進行管理。Windows Mobile 設備中心與高效的商務數據同步平臺緊密結合,提供了令人耳目一新的用戶體驗。Windows Mobile 設備中心可以幫助您快速建立新的合作關系,同步重要的商務信息(例如電子郵件、聯系人和日歷約會),輕松管理同步設置,以及在設備與 PC 間傳送商業文檔。
            這個主要是用于vista系統的。下載地址是
            http://www.microsoft.com/downloads/details.aspx?familyid=46F72DF1-E46A-4A5F-A791-09F07AAA1914&displaylang=zh-cn

            也可以建議大家去搜一下,我是在新浪上下載的。
            鏈接:http://down1.tech.sina.com.cn/download/down_contents/1183219200/35965.shtml

            posted @ 2008-11-19 19:37 Sandy 閱讀(1064) | 評論 (0)編輯 收藏

             

                    在csdn上閑逛,看到一個這樣的問題:如何在PPC上實現多語言的程序列表中的名稱在編譯時自動切換

                    這個曾經讓我相當苦惱,看到這個自然不會放過。


                     一位牛人很簡單的回答:
                
                  參考MUIHello 例子: 

                   C:\Program Files\Windows CE Tools\wce500\Windows Mobile 5.0 Smartphone SDK\Samples\CPP\Win32\Muihello\app\app.sln 
                  C:\Program Files\Windows CE Tools\wce500\Windows Mobile 5.0 Smartphone SDK\Samples\CPP\Win32\Muihello\German_resfile\german_resfile.sln 
                  C:\Program Files\Windows CE Tools\wce500\Windows Mobile 5.0 Smartphone SDK\Samples\CPP\Win32\Muihello\Resfile\resfile.sln

                  Samples竟然有多語言的例子,讓我相當的驚訝!
                 學習了一下,比我自己的方法簡單很多,看來需要好好學習SDK中提供的例子。

                 這個例子會生成muihello.exe.0409.mui,這其實是一個DLL資源文件,有人說這是一種命名規則。在不同的平臺上就調用不同的資源,實現多語言。

                  在resfile.cpp文件中

            #include "windows.h"

            /////////////////////////////////////////////////////////////////////////////
            // DLL Entry Point

            extern "C"
            BOOL WINAPI DllMain(HANDLE hInstance, DWORD dwReason, LPVOID lpReserved)
            {
                
            return TRUE; 
            }

                 還有一個文件resfile.def
                 
            LIBRARY      "muihello.exe.0409.mui"

            EXPORTS

                  而且resource.h是共用一個的。

                嘗試了一下,蠻好。
            posted @ 2008-11-18 22:22 Sandy 閱讀(1437) | 評論 (0)編輯 收藏

            Burning    by Maria Arredondo

            Passion is sweet

            Love makes weak

            You said you cherished freedom so

            You refused to let it go

            Follow your fate

            Love and hate

            Never failed to seize the day

            Don’t give yourself away

            Oh when the night falls

            And you’re all alone

            In your deepest sleep

            What are you dreaming of

            My skin is still burning from your touch

            Oh I just can’t get enough

            I said I wouldn’t ask for much

            But your eyes are dangerous

            So the world keeps spinning in my head

            Can we drop this masquerade

            I can’t predict where it ends

            If you’ re the rock I’ll crush against

            Trapped in a crowd

            Music is loud

            I said I loved my freedom too

            Now I’m not so sure I do

            All eyes on you

            Wings so true

            Better quit while you're a head

            Now I’m not so sure I am

            Oh when the night falls

            And you’re all alone

            In your deepest sleep

            What are you dreaming of

            My skin is still burning from your touch

            Oh I just can’t get enough

            I said I wouldn’t ask for much

            But your eyes are dangerous

            So the world keeps spinning in my head

            Can we drop this masquerade

            I can’t predict where it ends

            If you’ re the rock I’ll crush against

            My soul, my heart

            If you’re near or if you’re far

            My life, my love

            You can have it all

            posted @ 2008-11-12 09:18 Sandy 閱讀(150) | 評論 (0)編輯 收藏

            下面摘自http://www.shnenglu.com/woaidongmao/archive/2008/11/03/65897.html

            看到他們的在爭論很有意思,我不是很懂。

            有利還是有弊呢?


            EXT_ASSERT將ASSERT與if結合在一起

            ASSERT在DEBUG程序時候幫了太多太多忙,不過在ASSERT判斷傳入參數后,還需要if再按相同條件判斷一遍,不符合規則return,這樣才是正確的邏輯。但這樣代碼難看,且工作重復無趣,又容易出現差漏。

            剛弄了個簡單EXT_ASSERT宏,按我的理解應該可以解決問題,但不確定是否有漏洞,發出來大家一起瞄瞄。

             

            #define RET_VOID
            #define EX_ASSERT(exp, ret) {ASSERT(exp);if(!(exp))return(ret);}

             

            BOOL CXXX::FunXXX(const data* p_data)
            {
               EXT_ASSERT(p_data, FALSE);//---- 返回BOOL型

            }

            int CXXX::FunXXX(const data* p_data)
            {
               EXT_ASSERT(p_data, -1);//---- 返回int型

            }

            const retdata* CXXX::FunXXX(const data* p_data)
            {
                EXT_ASSERT(p_data, NULL);//---- 返回NULL指針

            }

            retdata CXXX::FunXXX(const data* p_data)
            {
                EXT_ASSERT(p_data, retdata());//---- 返回空對象

            }

            void CXXX::FunXXX(const data* p_data)
            {
                EXT_ASSERT(p_data, RET_VOID);//---- 僅僅return

            }

            posted on 2008-11-03 23:34 肥仔 閱讀(333) 評論(7)  編輯 收藏 引用 所屬分類: C++存檔

            評論

            # re: EXT_ASSERT將ASSERT與if結合在一起  回復  更多評論   

            哥們兒,如果你是說MFC里的ASSERT的話(看你的類命名風格,估計是吧),在retail build里,ASSERT是完全不會被放到代碼里的。你這樣用ASSERT,把ASSERT和if條件綁在一起就等于把處理錯誤的斷言和正常程序邏輯綁在了一起,不是一個好的設計。如果一定要這么干,也該是綁VERIFY,至少在retail build里VERIFY里的邏輯還會被執行。

            ASSERT應該拿來斷言程序正常執行完全不可能出現的錯誤(這些錯誤會在debug build里出現是因為當前程序還不完善),在正常邏輯中,他們是不應該用程序邏輯去handle的錯誤,所以一句ASSERT夠了。
            2008-11-04 05:27 | www.helpsoff.com.cn

            # re: EXT_ASSERT將ASSERT與if結合在一起  回復  更多評論   

            @www.helpsoff.com.cn
            我在Imperfect C++中看到過相同的言論。
            不過我的應用是,常常用ASSERT檢測參數的合法性,ASSERT之后,當然還要if一把了,對于ASSERT和if不要放在一起這種觀點,我不是很認同,我覺得放在一起很好用的。

            另外,在Release下,ASSERT沒了,但是if留下了,這是需要的效果。
            2008-11-04 10:45 | 肥仔

            # re: EXT_ASSERT將ASSERT與if結合在一起  回復  更多評論   

            我不會這么用,斷言的目的去那了。
            2008-11-04 11:30 | Touchsoft

            # re: EXT_ASSERT將ASSERT與if結合在一起  回復  更多評論   

            @肥仔
            哥們兒,你還是沒理解,ASSERT的不是拿來干這個的。你愛怎樣玩就怎樣玩吧,反正自己的代碼自己維護,其他人的意見聽不聽在你。
            2008-11-04 12:29 | www.helpsoff.com.cn

            # re: EXT_ASSERT將ASSERT與if結合在一起  回復  更多評論   

            @www.helpsoff.com.cn
            謝謝你的意見,但是不采納。原因有3點經歷:

            1、ASSERT判斷函數參數合法性,調試時會幫了很大的忙;
            2、if判段函數參數合法性,是健壯性的一部分;
            3、ASSERT和if 合在一起,不覺得有任何不妥,且ASSERT不出現在Release中,這正是需要的。

            可能涉及到的一個爭論是,檢測參數合法形是調用者,還是被調用者的責任?
            C/C++的主流是調用者保證參數的合法性,被調用者不檢測參數合法性,這就是為什么認為,只要ASSERT,不需要if了。
            strcpy(szBuf, NULL)之所以讓一個程序崩潰也是這個原因,但是為什么要讓它崩潰?能夠不崩潰,繼續執行豈不是更好嗎?
            2008-11-04 13:44 | 肥仔

            # re: EXT_ASSERT將ASSERT與if結合在一起  回復  更多評論   

            1) 沒人否認ASSERT的用處;
            2) 需要if判斷處理的參數和用ASSERT斷言的不合法參數,不應屬于一個范疇,不應該混合在一起處理;
            3) 代碼不管怎么寫在沒遇到問題前都不會有什么不妥,自己覺得好就好吧。

            你當然可以去寫一個萬能的strcpy,但是如何能保證你的strcpy是真正的“萬能”的呢?不崩潰繼續執行倒是沒問題,但是出問題的真正根源在哪里呢,你這樣做不就掩蓋了問題嗎?應該做的是出現這樣的問題時,能有用且有效的指出錯誤,而不是做garbage in, garbage out。

            設計代碼,不去扯那些玩得出花花的設計模式,有些很基本很直白的原則,比如說“garbage in, garbage out”,比如高內聚/低耦合...說多了也沒意思,樓主愛怎么玩怎么玩,大家都是這么過來的,其中的東西自己去體會了。
            2008-11-04 15:35 | www.helpsoff.com.cn

            # re: EXT_ASSERT將ASSERT與if結合在一起  回復  更多評論   

            @www.helpsoff.com.cn
            程序以外,人生很多地方都需要與別人探討,對于不合己見者,請不必太在懷,更沒必要帶著情緒和語氣,擺出姿態。這樣才能贏得更多的合作,我想我的這幾句話還算中肯。
            2008-11-04 16:32 | 肥仔
            posted @ 2008-11-04 18:28 Sandy 閱讀(394) | 評論 (0)編輯 收藏
            僅列出標題
            共15頁: First 7 8 9 10 11 12 13 14 15 
            久久久久久精品久久久久| 精品综合久久久久久97超人| 精品99久久aaa一级毛片| 久久久99精品成人片中文字幕| 日韩欧美亚洲国产精品字幕久久久 | 国产精品成人久久久| 伊人久久久AV老熟妇色| 国产成人久久精品区一区二区| 久久久久久久久久免免费精品| 99久久国产综合精品女同图片 | 亚洲精品成人网久久久久久| 一本色道久久88—综合亚洲精品| 久久久国产精品网站| 狠狠色婷婷久久一区二区| 91精品国产91久久久久久| 中文无码久久精品| 久久久久亚洲精品中文字幕| 韩国三级大全久久网站| 亚洲人成网亚洲欧洲无码久久| 色综合合久久天天综合绕视看| 亚洲色欲久久久综合网| 色偷偷91久久综合噜噜噜噜| 精品久久久久久无码中文野结衣| 无码AV波多野结衣久久| 久久成人18免费网站| 久久精品国产亚洲沈樵| 色综合久久综合中文综合网| 久久露脸国产精品| 久久93精品国产91久久综合| 精品久久久久久国产| 99久久久精品免费观看国产| 精品无码久久久久久尤物| 久久天天躁狠狠躁夜夜网站| 国产免费久久精品99re丫y| 久久综合久久伊人| 久久精品国产精品亜洲毛片| 日韩一区二区久久久久久| 91精品国产91久久久久久| 亚洲国产精品婷婷久久| 99久久免费只有精品国产| 久久免费精品一区二区|