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

            MyMSDN

            MyMSDN記錄開(kāi)發(fā)新知道

            #

            Expert C Programming notes

            1、const其實(shí)并不是真正的常量(P32)

            const_is_not_constant

            2、早期的gets()中的Bug導(dǎo)致了Internet蠕蟲(chóng)(P42)

            gets()函數(shù)并不檢查緩沖區(qū)的空間,事實(shí)上它也無(wú)法檢查緩沖區(qū)的空間。如果函數(shù)的調(diào)用者提供了一個(gè)指向堆棧的指針,并且gets()函數(shù)讀入的字符數(shù)量超過(guò)緩沖區(qū)的空間,gets()函數(shù)將會(huì)愉快地將多出來(lái)的字符繼續(xù)寫入到堆棧中,這就覆蓋了堆棧原先的內(nèi)容。——這就是病毒利用它來(lái)寫入額外空間,并引發(fā)蠕蟲(chóng)病毒的前提。

            推薦的方式是將

            gets(line)

            替換為

            if(fgets(line, sizeof(line), stdin) == NULL)

            exit(1);

            3、相鄰字符串常量自動(dòng)連接(P45)

            這個(gè)其實(shí)已經(jīng)應(yīng)用很普遍了,但是我個(gè)人用的比較少,特此記錄一下。

            ansi-c_connect_string

            4、返回一個(gè)指針?(P48)

            這個(gè)話題圍繞一個(gè)程序的BUG來(lái)展開(kāi),這個(gè)程序返回了局部變量的值的指針,這么說(shuō)當(dāng)然你一眼就能看得出來(lái)問(wèn)題所在,但是在很多時(shí)候,這個(gè)錯(cuò)誤卻總是在你的眼皮子底下溜走。

            作者提供了五種方式,只能說(shuō)可以用,但唯一推薦的只有一個(gè),詳見(jiàn)作者的分析(P48)(不是什么高深的理論,你自己也能分析地出來(lái))。

            a.返回一個(gè)字符串常量的指針。因?yàn)槌A看嬖陟o態(tài)數(shù)據(jù)存儲(chǔ)區(qū),所以指針沒(méi)問(wèn)題。

            b.使用全局聲明的數(shù)組。提到全局兩個(gè)字,就知道這個(gè)方法有很大的局限性。

            c.使用靜態(tài)數(shù)組。下一次調(diào)用將覆蓋這個(gè)數(shù)組內(nèi)容。

            char * func() {

            static char buffer[20];

            return buffer;

            }

            d.顯式分配一些內(nèi)存,保存返回的值。

            char  * func() {

            char * s = malloc(120);

            return s;

            }

            既然用到了malloc,就必然伴隨著free,因此帶來(lái)了內(nèi)存管理的問(wèn)題,增加了開(kāi)發(fā)者負(fù)擔(dān)。

            e.(推薦)在調(diào)用前后,由函數(shù)調(diào)用者分配內(nèi)存,并由其釋放,在同一地方釋放對(duì)于內(nèi)存管理來(lái)說(shuō)代價(jià)相對(duì)最小。

            void func( char * result, int size) {

            strncpy(result, “That’d be in the data segment, Bob”, size);

            }

            buffer = malloc(size);

            func(buffer, size);

            free(buffer);

            posted @ 2009-04-01 00:31 volnet 閱讀(323) | 評(píng)論 (0)編輯 收藏

            QuickSort快速排序法(2009-03-06)

            本文代碼已經(jīng)更新,修正嚴(yán)重BUG,最新版本詳見(jiàn)《QuickSort快速排序法(2009-10-28)》!

            本文中所涉及的代碼未做更新,請(qǐng)移步最新版查閱正確代碼!

            鏈接:http://www.shnenglu.com/mymsdn/archive/2009/10/28/quicksort20091028.html


            快速排序法:(好土,感覺(jué)滿世界都會(huì),不過(guò)還是寫一下,當(dāng)然了,標(biāo)準(zhǔn)庫(kù)里多的是排序算法),這里還是實(shí)現(xiàn)經(jīng)典版的快速排序了,時(shí)間復(fù)雜度O(nlogn)

            Algorithms.h

            #pragma once
            
            #include <iostream>
            
            class Algorithms
            {
            public:
                Algorithms(void);
                ~Algorithms(void);
            
            public:
                template <typename T>
                static void QuickSort(T* arr, size_t min, size_t max);
            private:
                template <typename T>
                static size_t qsort_helper_partition(T* arr, size_t min, size_t max);
                template <typename T>
                static inline void swap(T* arr, size_t x, size_t y);
            };
            
            template <typename T>
            void Algorithms::QuickSort(T* arr, size_t min, size_t max)
            {
                if(min >= max || max == 0 - 1) return;
                size_t p = qsort_helper_partition(arr, min, max);
            
                QuickSort(arr, min, p - 1);
                QuickSort(arr, p + 1, max);
            }
            
            template <typename T>
            size_t Algorithms::qsort_helper_partition(T* arr, size_t min, size_t max)
            {
                T cmp = arr[min];
                int i = min + 1, j = max;
                while(true)
                {
                    while(cmp < arr[i])
                        ++i;
                    while(arr[j] < cmp)
                        --j;
                    if(i >= j) break;
            
                    swap(arr, i, j);
                }
                swap(arr, min, j);
                return j;
            }
            
            template <typename T>
            void Algorithms::swap(T* arr, size_t x, size_t y)
            {
                T tmp = arr[x];
                arr[x] = arr[y];
                arr[y] = tmp;
            }

            用法:(順便有標(biāo)準(zhǔn)庫(kù)的排序法,當(dāng)然只是調(diào)一下,沒(méi)有什么可說(shuō)的了)

            #include "Algorithms.h"
            #include <iostream>
            #include <vector>
            #include <algorithm>
            
            int _tmain(int argc, _TCHAR* argv[])
            {
                int arr[] = {4, 8, 3, 7, 1, 5, 6, 2};
            
                for(size_t i = 0; i != 8; ++i)
                {
                    std::cout<<arr[i]<<" ";
                }
                std::cout<<std::endl;
            
                Algorithms::QuickSort(arr,0, 7);
            
                for(size_t i = 0; i != 8; ++i)
                {
                    std::cout<<arr[i]<<" ";
                }
                std::cout<<std::endl;
            
                std::vector<int> vec;
                vec.push_back(3);
                vec.push_back(1);
                vec.push_back(4);
                vec.push_back(1);
                vec.push_back(7);
                vec.push_back(6);
            
                for(std::vector<int>::iterator iter = vec.begin();
                    iter != vec.end(); ++ iter)
                {
                    std::cout<<*iter<<" ";
                }
                std::cout<<std::endl;
            
                std::sort(vec.begin(), vec.end());
            
                for(std::vector<int>::iterator iter = vec.begin();
                    iter != vec.end(); ++ iter)
                {
                    std::cout<<*iter<<" ";
                }
                std::cout<<std::endl;
            
                return 0;
            }
            
            

            posted @ 2009-03-06 03:03 volnet 閱讀(1201) | 評(píng)論 (5)編輯 收藏

            最大公約數(shù)問(wèn)題

            image

            image

            image

            image

            image 

            image

            image

            image

            image

            以上內(nèi)容摘自《編程之美》P150-154。

            為了方便使用,下面是可拷貝的代碼:

            Math.h

            #pragma once
            
            class Math
            {
            public:
                Math(void);
                ~Math(void);
            
            public :
                //編程之美P150-154
            
                //求最大公約數(shù),歐幾里德——輾轉(zhuǎn)相除法
                static int Gcd1(int x, int y);
            
                //求最大公約數(shù),歐幾里德——輾轉(zhuǎn)相除法(變相將除法變成了減法)
                static int Gcd2(int x, int y);
            
                static int Gcd3(int x, int y);
            
                inline static bool IsEven(int x);
            
                inline static int Absolute(int x);
            };
            

            Math.cpp

            #include "Math.h"
            
            Math::Math(void)
            {
            }
            
            Math::~Math(void)
            {
            }
            
            int Math::Gcd1(int x, int y)
            {
                //y, x%y順序不能錯(cuò);
                return y ? Gcd1(y, x % y) : x;
            }
            
            int Math::Gcd2(int x, int y)
            {
                //與Gcd1相同的方式,但由于x%y計(jì)算速度較x-y要慢,但效果相同,所以換用x - y
                // 但用減法和除法不同的是,比如和,%20=10,-20=70,也就是-4×=10
                // 也就是說(shuō)迭代次數(shù)較Gcd1而言通常是增加了。
                return y ? Gcd1(y, x - y) : x;
            }
            
            int Math::Gcd3(int x, int y)
            {
                if(x < y)
                    return Gcd3(y, x);
                if(y == 0)
                    return x;
                else
                {
                    if(IsEven(x))
                    {
                        if(IsEven(y))
                            return (Gcd3(x >> 1, y >> 1) << 1);
                        else
                            return Gcd3(x >> 1, y);
                    }
                    else
                    {
                        if(IsEven(y))
                            return Gcd3(x, y >> 1);
                        else
                            return Gcd3(y, x - y);
                    }
                }
            }
            
            bool Math::IsEven(int x)
            {
                return !(bool)x & 0x0001;
            }
            
            int Math::Absolute(int x)
            {
                return x < 0 ? -x : x;
            }

            Main.cpp

            #include <stdafx.h>
            #include <iostream>
            #include "Math.h"
            
            using namespace std;
            int _tmain(const int & arg)
            {
                cout<<"Math::Gcd1(42,30) = "<<Math::Gcd1(42,30)<<endl;
                cout<<"Math::Gcd1(30,42) = "<<Math::Gcd1(30,42)<<endl;
                cout<<"Math::Gcd1(50,50) = "<<Math::Gcd1(50,50)<<endl;
                cout<<"Math::Gcd1(0,0) = "<<Math::Gcd1(0,0)<<endl;
                cout<<"Math::Gcd1(-42,-30) = "<<Math::Gcd1(-42,-30)<<endl;
                cout<<"Math::Gcd1(-42,30) = "<<Math::Gcd1(-42,30)<<endl;
            
                cout<<"------------------------------"<<endl;
            
                cout<<"Math::Gcd2(42,30) = "<<Math::Gcd2(42,30)<<endl;
                cout<<"Math::Gcd2(30,42) = "<<Math::Gcd2(30,42)<<endl;
                cout<<"Math::Gcd2(50,50) = "<<Math::Gcd2(50,50)<<endl;
                cout<<"Math::Gcd2(0,0) = "<<Math::Gcd2(0,0)<<endl;
                cout<<"Math::Gcd2(-42,-30) = "<<Math::Gcd2(-42,-30)<<endl;
                cout<<"Math::Gcd2(-42,30) = "<<Math::Gcd2(-42,30)<<endl;
            
                cout<<"------------------------------"<<endl;
            
                cout<<"Math::Gcd3(42,30) = "<<Math::Gcd3(42,30)<<endl;
                cout<<"Math::Gcd3(30,42) = "<<Math::Gcd3(30,42)<<endl;
                cout<<"Math::Gcd3(50,50) = "<<Math::Gcd3(50,50)<<endl;
                cout<<"Math::Gcd3(0,0) = "<<Math::Gcd3(0,0)<<endl;
                cout<<"Math::Gcd3(-42,-30) = "<<Math::Gcd3(-42,-30)<<endl;
                cout<<"Math::Gcd3(-42,30) = "<<Math::Gcd3(-42,30)<<endl;
            
                return 0;
            }

            不過(guò)有一點(diǎn)值得一提,就是所謂性能最好效率最高的Gcd3不支持負(fù)數(shù),也就是最后兩行測(cè)試代碼無(wú)法通過(guò)。但是限于對(duì)負(fù)數(shù)的最大公約數(shù)并沒(méi)有定義,也就是說(shuō)即便上面的Gcd1和Gcd2好像算出了負(fù)數(shù),但它們的結(jié)果沒(méi)有意義。

            posted @ 2009-03-04 23:52 volnet 閱讀(1029) | 評(píng)論 (0)編輯 收藏

            a Swap program

            #include "stdio.h"
            #include "stdlib.h"
            
            void foo(int *a, int *b) {
                *a = *a + *b;
                *b = *a - *b;
                *a = *a - *b;
            }
            int main(void) {
                int a = 1, b = 2, c = 3;
                foo(&a, &b);
                foo(&b, &c);
                foo(&c, &a);
                printf("%d, %d, %d", a, b, c);
                return EXIT_SUCCESS;
            }

            foo看似繚亂卻是一個(gè)交換函數(shù):

            從最后一次做*a和*b的位置開(kāi)始向上:

            也就是*b = *a - *b;擴(kuò)展為*b = (*a + *b) - *b展開(kāi)就是*b = *a;也就是將*a的值賦給了*b。(注意到在此之前*b從未改變過(guò))

            *a = *a - *b(這時(shí)候不能用上一行的結(jié)論,因?yàn)?a曾經(jīng)改變過(guò)了)擴(kuò)展為*a = (*a + *b) – *a 也就是*a = *b,這里*b是指原始的*b,而不是上一行的結(jié)論,至此就交換完畢。

            可以注意到,這里并沒(méi)有使用臨時(shí)變量。所以這是一個(gè)不需要臨時(shí)變量的交換方法。不過(guò)這種方法只支持支持operator+和operator-的數(shù)值計(jì)算(基本上只能用在整數(shù)上,因?yàn)閷?duì)浮點(diǎn)的操作可能涉及到舍入的問(wèn)題)

            而且這個(gè)方法還有一個(gè)缺陷,就是對(duì)數(shù)值邊界的判斷,比入MAX_INT+MAX_INT就溢出了,所以它存在一定的局限性。

            posted @ 2009-02-24 18:29 volnet 閱讀(279) | 評(píng)論 (0)編輯 收藏

            關(guān)于C++ Template分離頭文件和定義所產(chǎn)生的錯(cuò)誤

            編譯錯(cuò)誤

            如圖所示的代碼出現(xiàn)了如圖所示的錯(cuò)誤,誰(shuí)能解釋一下是為什么呢?

            雖然在最后include進(jìn)了cpp文件,而且這種做法也在C++ Primer中也是正確的(難道是標(biāo)準(zhǔn)和現(xiàn)實(shí)的差距?)。將代碼稍微變動(dòng),并將cpp部分的內(nèi)容移到.h文件中的include位置即可正確編譯。

            編譯正確

            posted @ 2009-02-22 06:05 volnet 閱讀(4340) | 評(píng)論 (20)編輯 收藏

            將數(shù)組作為實(shí)參傳遞

            在C++中我們應(yīng)該少用指針,多用引用,原因請(qǐng)大家自行搜索。在傳遞數(shù)組的時(shí)候我們需要格外注意,先讓我們看一個(gè)簡(jiǎn)單的范例。

            // PassArray.cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)。
            //
            
            #include "stdafx.h"
            #include <iostream>
            
            using namespace std;
            
            template <typename T>
            void Func1(T, T);
            template <typename T>
            void Func2(T&, T&);
            void Func3(int (&)[10], int (&)[12]);
            
            int _tmain(int argc, _TCHAR* argv[])
            {
                int a[10], b[12];
            
                Func1(a, b);
                Func2(a, b);
                Func3(a, b);
            
                return 0;
            }
            
            template <typename T>
            void Func1(T, T)
            {
                cout<<"Func1.invoked!"<<endl;
            }
            template <typename T>
            void Func2(T&, T&)
            {
                cout<<"Func2.invoked!"<<endl;
            }
            void Func3(int (&m)[10], int (&n)[12])
            {
                cout<<"Func3.invoked!"<<endl;
            }

            首先這個(gè)范例無(wú)法編譯通過(guò):

            error C2782

            原因就出在類型推斷上。根據(jù)定義,F(xiàn)unc2的類型必須是T&,也就是說(shuō)傳遞實(shí)參的時(shí)候,兩個(gè)形參必須是相同的,而這一點(diǎn)在模板編程中就會(huì)由編譯器來(lái)負(fù)責(zé)推斷。

            Func1:

            調(diào)用Func1(a, b)則推斷的類型分別是Func1(int*, int*),調(diào)用函數(shù)將會(huì)自動(dòng)將數(shù)組的首地址指針作為實(shí)參進(jìn)行傳遞,因此類型推斷兩形參相同,編譯通過(guò)!

            Func2:

            調(diào)用Func2(a, b)因?yàn)槲覀兿M匆玫姆绞竭M(jìn)行實(shí)參傳遞,因此需要遵循這樣的規(guī)律:

            (P208)如果形參是數(shù)組的引用,編譯器將不會(huì)將數(shù)組實(shí)參轉(zhuǎn)化為指針,而是傳遞數(shù)組引用的本身。在這種情況下,數(shù)組大小成為形參和實(shí)參類型的一部分。

            所以推斷類型分別是Func2(int (&)[10], int (&)[12]),因?yàn)閕nt (&)[10] != int (&)[12],所以與T == T相悖!自然也就編譯不過(guò)了!

            Func3:

            該函數(shù)是Func2的一個(gè)靜態(tài)表示,通過(guò)上面的解釋應(yīng)該很容易理解這個(gè)代碼了。

            posted @ 2009-02-19 21:35 volnet 閱讀(1716) | 評(píng)論 (0)編輯 收藏

            計(jì)時(shí)器代碼片段

            這不是一個(gè)面向?qū)ο蟮拇a庫(kù),它的存在僅僅只是為了說(shuō)明幾個(gè)函數(shù)調(diào)用,如果要在您的工程中應(yīng)用相關(guān)內(nèi)容,請(qǐng)自行構(gòu)建(這應(yīng)該不難),或者看看我推薦的文檔。

            // ProcessAffinity.cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)。
            //
            
            #include "stdafx.h"
            #include <windows.h>
            #include <iostream>
            #include <vector>
            
            using namespace std;
            void DisplayFrequency(ostream &out, LARGE_INTEGER &freq);
            
            struct TimeSpan
            {
                LARGE_INTEGER *Frequency;
                LARGE_INTEGER StartCounter;
                LARGE_INTEGER StopCounter;
                BOOL HAS_ERROR;
                double CalTimeSpan(){
                    return (StopCounter.QuadPart - StartCounter.QuadPart)/Frequency->QuadPart;
                }
            };
            
            int _tmain(int argc, _TCHAR* argv[])
            {
                HANDLE CurrentProcessHandle;
                DWORD ProcessAffinityMask, SystemAffinityMask, AllowProcessAffinity;
            
                CurrentProcessHandle = GetCurrentProcess();
            
                //GetCurrentProcess返回一個(gè)常量,代表當(dāng)前的進(jìn)程句柄
                cout<<CurrentProcessHandle<<endl;
                cout<<(HANDLE)-1<<endl;
                cout<<(void*)-1<<endl;
                cout<<(void*)0xffffffff<<endl;
            
                cout<<"-----------------------------"<<endl;
            
                if(GetProcessAffinityMask(CurrentProcessHandle, &ProcessAffinityMask, &SystemAffinityMask))
                {
                    cout<<ProcessAffinityMask<<endl;    //0x0001
                    cout<<SystemAffinityMask<<endl;        //0x0001
                
                    AllowProcessAffinity = ProcessAffinityMask & SystemAffinityMask;
                    cout<<AllowProcessAffinity<<endl;
                }
            
                LARGE_INTEGER Freq;
                typedef vector<LARGE_INTEGER> FreqVec_type;
                FreqVec_type FreqVec;
                
                while(FreqVec.size() != 5)
                {
                    if(QueryPerformanceFrequency(&Freq))
                    {
                        DisplayFrequency(cout, Freq);
                        FreqVec.push_back(Freq);
                    }
                    Sleep(1000);
                }
            
                for(FreqVec_type::iterator iter = FreqVec.begin(); iter!=FreqVec.end(); ++iter)
                {
                    DisplayFrequency(cout, *iter);
                }
            
                cout<<"---------------------"<<endl;
            
                //calculate the timeSpan;
                TimeSpan ts;
                int sleepTime(3123);
            
                ts.Frequency = &Freq;
            
                if(QueryPerformanceCounter(&ts.StartCounter))
                {
                    ts.HAS_ERROR = false;
                    Sleep(sleepTime);
                }
                if(!ts.HAS_ERROR)
                {
                    QueryPerformanceCounter(&ts.StopCounter);
                }
                
                cout<<ts.CalTimeSpan()<<endl;
                cout<<(ts.StopCounter.QuadPart-ts.StartCounter.QuadPart)/sleepTime<<endl;
            
                return 0;
            }
            
            void DisplayFrequency(ostream &out, LARGE_INTEGER &freq)
            {
                out<<"start display!"<<endl;
                out<<freq.HighPart<<endl;
                out<<freq.LowPart<<endl;
                out<<freq.QuadPart<<endl;
                out<<"end display!"<<endl;
            }
            
            

            推薦文檔:《使用增強(qiáng)的計(jì)時(shí)器測(cè)量代碼段》(下載可適合打印,已排版,閱讀該文檔需要使用Microsoft Word 2007或相關(guān)閱讀器(后綴docx),如您需要pdf文檔,可以給我留言,我會(huì)將它發(fā)給你,在CSDN的下載中,您可能需要注冊(cè)成為相關(guān)網(wǎng)站的會(huì)員,或者使用積分,如果您覺(jué)得麻煩,可以直接向我索取!點(diǎn)此獲取!

            posted @ 2009-02-19 01:49 volnet 閱讀(653) | 評(píng)論 (0)編輯 收藏

            什么是句柄?為什么會(huì)有句柄?HANDLE

            關(guān)鍵字:句柄, HANDLE, WINDOWS SDK, windows.h,

            從廣義上,能夠從一個(gè)數(shù)值拎起一大堆數(shù)據(jù)的東西都可以叫做句柄。句柄的英文是"Handle",本義就是"柄",只是在計(jì)算機(jī)科學(xué)中,被特別地翻譯成"句柄",其實(shí)還是個(gè)"柄"。從一個(gè)小東西拎起一大堆東西,這難道不像是個(gè)"柄"嗎?

            然后,指針其實(shí)也是一種"句柄",只是由于指針同時(shí)擁有更特殊的含義——實(shí)實(shí)在在地對(duì)應(yīng)內(nèi)存里地一個(gè)地址——所以,通常不把指針說(shuō)成是"句柄"。但指針也有著能從一個(gè)32位的值引用到一大堆數(shù)據(jù)的作用,這不是句柄又是什么?

            Windows系統(tǒng)中有許多內(nèi)核對(duì)象(這里的對(duì)象不完全等價(jià)于"面向?qū)ο蟪绦蛟O(shè)計(jì)"一詞中的"對(duì)象",雖然實(shí)質(zhì)上還真差不多),比如打開(kāi)的文件,創(chuàng)建的線程,程序的窗口,等等。這些重要的對(duì)象肯定不是4個(gè)字節(jié)或者8個(gè)字節(jié)足以完全描述的,他們擁有大量的屬性。為了保存這樣一個(gè)"對(duì)象"的狀態(tài),往往需要上百甚至上千字節(jié)的內(nèi)存空間,那么怎么在程序間或程序內(nèi)部的子過(guò)程(函數(shù))之間傳遞這些數(shù)據(jù)呢?拖著這成百上千的字節(jié)拷貝來(lái)拷貝去嗎?顯然會(huì)浪費(fèi)效率。那么怎么辦?當(dāng)然傳遞這些對(duì)象的首地址是一個(gè)辦法,但這至少有兩個(gè)缺點(diǎn):

            1. 暴露了內(nèi)核對(duì)象本身,使得程序(而不是操作系統(tǒng)內(nèi)核)也可以任意地修改對(duì)象地內(nèi)部狀態(tài)(首地址都知道了,還有什么不能改的?),這顯然是操作系統(tǒng)內(nèi)核所不允許的;
            2. 操作系統(tǒng)有定期整理內(nèi)存的責(zé)任,如果一些內(nèi)存整理過(guò)一次后,對(duì)象被搬走了怎么辦?

            所以,Windows操作系統(tǒng)就采用進(jìn)一步的間接:在進(jìn)程的地址空間中設(shè)一張表,表里頭專門保存一些編號(hào)和由這個(gè)編號(hào)對(duì)應(yīng)一個(gè)地址,而由那個(gè)地址去引用實(shí)際的對(duì)象,這個(gè)編號(hào)跟那個(gè)地址在數(shù)值上沒(méi)有任何規(guī)律性的聯(lián)系,純粹是個(gè)映射而已。

            在Windows系統(tǒng)中,這個(gè)編號(hào)就叫做"句柄"。

            ?

            Handle在Windows中的含義很廣泛,以下關(guān)于談到的Handle除非特別說(shuō)明,將僅限于進(jìn)程、線程的上下文中。

            1、先來(lái)談?wù)凥andle

            Handle本身是一個(gè)32位的無(wú)符號(hào)整數(shù),它用來(lái)代表一個(gè)內(nèi)核對(duì)象。它并不指向?qū)嶋H的內(nèi)核對(duì)象,用戶模式下的程序永遠(yuǎn)不可能獲得一個(gè)內(nèi)核對(duì)象的實(shí)際地址(一般情況下)。那么Handle的意義何在?它實(shí)際上是作為一個(gè)索引在一個(gè)表中查找對(duì)應(yīng)的內(nèi)核對(duì)象的實(shí)際地址。那么這個(gè)表在哪里呢?每個(gè)進(jìn)程都有這樣的一個(gè)表,叫句柄表。該表的第一項(xiàng)就是進(jìn)程自己的句柄,這也是為什么你調(diào)用GetCurrentProcess()總是返回0x7FFFFFFF原因。

            簡(jiǎn)單地說(shuō),Handle就是一種用來(lái)"間接"代表一個(gè)內(nèi)核對(duì)象的整數(shù)值。你可以在程序中使用handle來(lái)代表你想要操作的內(nèi)核對(duì)象。這里的內(nèi)核對(duì)象包括:事件(Event)、線程、進(jìn)程、Mutex等等。我們最常見(jiàn)的就是文件句柄(file handle)。

            另外要注意的是,Handle僅在其所屬的進(jìn)程中才有意義。將一個(gè)進(jìn)程擁有的handle傳給另一個(gè)進(jìn)程沒(méi)有任何意義,如果非要這么做,則需要使用DuplicateHandle(),在多個(gè)進(jìn)程間傳遞Handle是另外一個(gè)話題了,與這里要討論的無(wú)關(guān)。

            2、進(jìn)程ID

            首先,進(jìn)程ID是一個(gè)32位無(wú)符號(hào)整數(shù),每個(gè)進(jìn)程都有這樣的一個(gè)ID,并且該ID在系統(tǒng)范圍內(nèi)是唯一的。系統(tǒng)使用該ID來(lái)唯一確定一個(gè)進(jìn)程。

            深入些說(shuō),系統(tǒng)可能使用進(jìn)程ID來(lái)計(jì)算代表該進(jìn)程的內(nèi)核對(duì)象的基地址(及EPROCESS結(jié)構(gòu)的基地址),具體的計(jì)算公式你可以去問(wèn)微軟的OS開(kāi)發(fā)人員。

            3、HINSTANCE

            HINSTANCE也是一個(gè)32無(wú)符號(hào)整數(shù),它表示程序加載到內(nèi)存中的基地址。

            posted @ 2009-02-19 00:10 volnet 閱讀(25639) | 評(píng)論 (29)編輯 收藏

            C++ notes (6)

            51、static成員函數(shù)

            因?yàn)閟tatic成員不是任何對(duì)象的組成部分,所以static成員函數(shù)不能被聲明為const。畢竟,將成員函數(shù)聲明為const就是承諾不會(huì)修改該函數(shù)所屬的對(duì)象。最后,static成員函數(shù)也不能被聲明為虛函數(shù)。

            52、特殊的整型const static成員(P401)

            const static數(shù)據(jù)成員在類的定義體中初始化時(shí),該數(shù)據(jù)成員仍必須在類的定義體之外進(jìn)行定義。

            class Accout{

            public:

            static double rate() { return interestRate;}

            static void rate(double); //sets a new rate

            private:

            static const int period = 30; //interest posted every 30 days

            double daily_tbl[period]; // ok: period is constant expression

            }

            //definition of static member with no initializer;

            //the initial value is specified inside the class definition

            const int Accout::period;

            但在gcc和MS vc++編譯器下似乎均不需要再次定義,也就是題設(shè)的“必須”二字在此失效。

            53、操作符重載(P435)

            下面是一些指導(dǎo)原則,有助于決定將操作符設(shè)置為類成員還是普通非成員函數(shù)

            • 賦值(=)、下標(biāo)([])、調(diào)用(())和成員訪問(wèn)箭頭(->)等操作符必須定義為成員,將這些操作符定義為非成員函數(shù)將在編譯時(shí)標(biāo)記為錯(cuò)誤。
            • 像賦值一樣,復(fù)合賦值操作符通常應(yīng)定義為類的成員。與賦值不同的是,不一定非得這樣做,如果定義非成員復(fù)合賦值操作符,不會(huì)出現(xiàn)編譯錯(cuò)誤。
            • 改變對(duì)象狀態(tài)或與給定類型緊密聯(lián)系的其他一些操作符,如自增、自減和解引用,通常應(yīng)定義為類成員。
            • 對(duì)稱的操作符,如算術(shù)操作符、相等操作符、關(guān)系操作符和位操作符,最好定義為普通非成員函數(shù)。

            54、區(qū)別操作符的前綴和后綴形式(P447)

            同時(shí)定義前綴式操作符和后綴式操作符存在一個(gè)問(wèn)題:它們的形參數(shù)目和類型相同,普通重載不能區(qū)別所定義的是前綴式操作符還是后綴式操作符。

            為解決這一問(wèn)題,后綴式操作符函數(shù)接受一個(gè)額外的(即,無(wú)用的)int型形參。使用后綴操作符時(shí),編譯器提供0作為這個(gè)形參的實(shí)參。盡管我們的前綴式操作符函數(shù)可以使用這個(gè)額外的形參,但通常不應(yīng)該這樣做。那個(gè)形參不是后綴式操作符的正常工作所需要的,它的唯一目的是使后綴函數(shù)與前綴函數(shù)區(qū)別開(kāi)來(lái)。

            55、顯式調(diào)用前綴式操作符

            CheckedPtr parr(ia, ia+size); //ia points to an array of ints

            parr.operator(0); //call postfix operator++

            parr.operator(); //call prefix operator++

            56、函數(shù)對(duì)象(P450)

            struct absInt {

            int operator() (int val){

                   return val<0 ? –val : val;

            }

            };

            int i = –42;

            absInt absObj; //object that defines function call operator

            unsigned int ui = absObj(i); //calls absInt::operator(int)

            盡管absObj是一個(gè)對(duì)象而不是函數(shù),我們?nèi)匀豢梢?#8220;調(diào)用”該對(duì)象,效果是運(yùn)行由absObj對(duì)象定義的重載調(diào)用操作符,該操作符接受一個(gè)int值并返回它的絕對(duì)值。

            函數(shù)對(duì)象經(jīng)常用作通用算法的實(shí)參。(詳見(jiàn)P450)

            57、函數(shù)對(duì)象的函數(shù)適配器(P453)

            標(biāo)準(zhǔn)庫(kù)提供了一組函數(shù)適配器(function adapter),用于特化和擴(kuò)展一元和二元函數(shù)對(duì)象。函數(shù)適配器分為如下兩類:

            (1)綁定器(binder),是一種函數(shù)適配器,它通過(guò)將一個(gè)操作數(shù)綁定到給定值而將二元函數(shù)對(duì)象轉(zhuǎn)換為一元函數(shù)對(duì)象。(bind1stbind2nd 更多

            (2)求反器(negator),是一種函數(shù)適配器,它將謂詞函數(shù)對(duì)象的真值求反。(not1not2 更多

            58、轉(zhuǎn)換操作符(P455)

            轉(zhuǎn)換為什么有用?(詳見(jiàn)P454)

            轉(zhuǎn)換函數(shù)采用如下通用形式:

            operator type();

            這里,type表示內(nèi)置類型名、類類型名或由類型別名所定義的名字。對(duì)任何可作為函數(shù)返回類型的類型(除了void之外)都可以定義轉(zhuǎn)換函數(shù)。一般而言,不允許轉(zhuǎn)換為數(shù)組或函數(shù)類型,轉(zhuǎn)換為指針(數(shù)據(jù)或函數(shù)指針)以及引用類型是可以的。

            轉(zhuǎn)換函數(shù)必須是成員函數(shù),不能指定返回類型,并且形參表必須為空。

            轉(zhuǎn)換函數(shù)一般不應(yīng)該改變被轉(zhuǎn)換的對(duì)象。因此,轉(zhuǎn)換操作符通常應(yīng)定義為const成員。

            59、只能應(yīng)用一個(gè)類類型轉(zhuǎn)換

            類類型轉(zhuǎn)換之后不能再跟另一個(gè)類類型轉(zhuǎn)換。如果需要多個(gè)類類型轉(zhuǎn)換,則代碼將出錯(cuò)。

            假設(shè)有Integral=>SmallInt=>int,但是如果有一個(gè)函數(shù)cal(int),那么對(duì)于SmallInt si,可以使用cal(si),但對(duì)于Integral intVal;則不能使用cal(intVal)。語(yǔ)言只允許一次類類型轉(zhuǎn)換,所以該調(diào)用出錯(cuò)。

            60、virtual與其他成員函數(shù)(P479)

            C++中的函數(shù)調(diào)用默認(rèn)不使用動(dòng)態(tài)綁定。要觸發(fā)動(dòng)態(tài)綁定,必須滿足兩個(gè)條件:第一,只有指定為虛函數(shù)的成員函數(shù)才能進(jìn)行動(dòng)態(tài)綁定,成員函數(shù)默認(rèn)為非虛函數(shù),非虛函數(shù)不進(jìn)行動(dòng)態(tài)綁定;第二,必須通過(guò)基類類型的引用或指針進(jìn)行函數(shù)調(diào)用。

            基類類型引用和指針的關(guān)鍵點(diǎn)在于靜態(tài)類型(static type,在編譯時(shí)可知的引用類型或指針類型)和動(dòng)態(tài)類型(dynamic type,指針或引用所綁定的對(duì)象的類型,這是僅在運(yùn)行時(shí)可知的)可能不同。

            posted @ 2009-02-15 02:28 volnet 閱讀(508) | 評(píng)論 (0)編輯 收藏

            C++ notes (5)

            41、vector、list、deque的性能初窺

            int large_size = 10000000;
            
            cout_current_time("start init vector!\t");
            vector<string> svec1(large_size, "Hello");
            vector<string> svec2(large_size, "Hi");
            cout_current_time("end init vector!\t");
            
            cout_current_time("start init list!\t");
            list<string> slist1(large_size, "Hello");
            list<string> slist2(large_size, "Hi");
            cout_current_time("end init list!\t");
            
            cout_current_time("start init deque!\t");
            deque<string> sdeq1(large_size, "Hello");
            deque<string> sdeq2(large_size, "Hi");
            cout_current_time("end init deque!\t");

            用事實(shí)說(shuō)話最有說(shuō)服力:

            start init vector!    current time : 5:5:52
            end init vector!    current time : 5:5:55
            start init list!    current time : 5:5:55
            end init list!    current time : 5:6:14
            start init deque!    current time : 5:6:14
            end init deque!    current time : 5:6:26

            可以看出大致時(shí)間比例為3/19/12。雖然不足以佐證它們的性能差距,但vector的常用似乎有了更充分的理由。

            這里使用了一個(gè)簡(jiǎn)單的時(shí)間函數(shù)大致如下:

            #include <time.h>
            
            typedef struct
            tm * time_type; time_type get_current_time(void) { time_t t; t = time(NULL); return localtime(&t); }

            42、容器自增長(zhǎng)(P286)

            每種實(shí)現(xiàn)都要求遵循以下原則:確保push_back操作高效地在vector中添加元素。從技術(shù)上來(lái)說(shuō),在原來(lái)為空的vector容器上n次調(diào)用push_back函數(shù),從而創(chuàng)建擁有n個(gè)元素的vector容器,其執(zhí)行時(shí)間永遠(yuǎn)不能超過(guò)n的常量倍。

            43、類定義中為何不能具有自身的數(shù)據(jù)成員(P375)

            因?yàn)橹挥挟?dāng)類定義體完成后才能定義類,因此類不能具有自身類型的數(shù)據(jù)成員。然而,只要類名一出現(xiàn)就可以認(rèn)為該類已聲明。因此,類的數(shù)據(jù)成員可以是指向自身類型的指針或引用:

            class LinkScreen {

            Screen window;

            LinkScreen *next;

            LinkScreen *prev;

            };

            44、兩種引用類類型的方法(P376)

            Sales_item item1; //default initialized object of type Sales_item

            class Sales_item item1; //equivalent definition of item1

            兩種引用類類型的方法是等價(jià)的。第二種方法是從C繼承而來(lái)的,在C++中仍然有效。第一種更為簡(jiǎn)練,由C++語(yǔ)言引入,使得類類型更容易使用。

            45、為什么類的定義以分號(hào)結(jié)束(P376)

            分號(hào)是必須的,因?yàn)樵陬惗x之后可以接一個(gè)對(duì)象定義列表。定義必須以分號(hào)結(jié)束:

            class Sales_item {/* … */};

            class Sales_item {/* … */} accum, trans;

            46、形參表和函數(shù)體處于類作用域中,函數(shù)返回類型不一定在類作用域中

            在定義于類外部的成員函數(shù)中,形參表和成員函數(shù)體都出現(xiàn)在成員名之后。這些都是在類作用域中定義,所以可以不用限定而引用其他成員。因?yàn)樾螀⒈硎窃赟creen類作用域內(nèi),所以不必知名我們想要的是Screen::index。

            如果返回類型使用由類定義的類型,則必須使用完全限定名。

            #include "stdafx.h"
            #include <iostream>
            
            class MyClass
            {
            public :
                typedef int index_t;
                index_t twice(index_t in);
            };
            
            MyClass::index_t MyClass ::twice(index_t in)
            {
                return in * 2;
            }
            
            int _tmain(int argc, _TCHAR* argv[])
            {
                using namespace std; 
                
                MyClass obj;
                MyClass::index_t x, y;
                
                x = 10;
                y = obj.twice(x);
            
                cout<<"x = "<<x<<"; y = "<<y<<";"<<endl;
            
                return 0;
            }

            47、構(gòu)造函數(shù)初始化式(P387)

            與任意的成員函數(shù)一樣,構(gòu)造函數(shù)可以定義在類的內(nèi)部或外部。構(gòu)造函數(shù)初始化式只在構(gòu)造函數(shù)的定義中而不是聲明中指定。

            構(gòu)造函數(shù)初始化列表難以理解的一個(gè)原因在于,省略初始化列表并在構(gòu)造函數(shù)的函數(shù)體內(nèi)對(duì)數(shù)據(jù)成員賦值是合法的。

            在構(gòu)造函數(shù)初始化列表中沒(méi)有顯式提及的每個(gè)成員,使用與初始化變量相同的規(guī)則來(lái)進(jìn)行初始化。運(yùn)行該類型的默認(rèn)構(gòu)造函數(shù),來(lái)初始化類類型的數(shù)據(jù)成員。內(nèi)置或復(fù)合類型的成員的初始值依賴于對(duì)象的作用域:在局部作用域中這些成員不被初始化,而在全局作用域中它們被初始化為0。

            如果那個(gè)類沒(méi)有默認(rèn)構(gòu)造函數(shù),則編譯器嘗試使用默認(rèn)構(gòu)造函數(shù)將會(huì)失敗。在這種情況下,為了初始化數(shù)據(jù)成員,必須提供初始化式。

            對(duì)于這樣的成員,在構(gòu)造函數(shù)函數(shù)體中對(duì)它們賦值不起作用。沒(méi)有默認(rèn)構(gòu)造函數(shù)的類類型成員,以及const或引用類型的成員,不管是哪種類型,都必須在構(gòu)造函數(shù)初始化列表中進(jìn)行初始化。

            因?yàn)閮?nèi)置類型的成員不進(jìn)行隱式初始化,所以對(duì)這些成員是進(jìn)行初始化還是賦值似乎都無(wú)關(guān)緊要。除了兩個(gè)例外,對(duì)非類類型的數(shù)據(jù)成員進(jìn)行賦值或使用初始化式在結(jié)果和性能上都是等價(jià)的。

            48、成員初始化的次序

            構(gòu)造函數(shù)初始化列表僅指定用于初始化成員的值,并不指定這些初始化執(zhí)行的次序。成員被初始化的次序就是定義成員的次序。

            class X{

            int i;

            int j;

            public:

            //run-time error: i is initialized before j

            X(int val): j(val), i(j) {}

            }

            在這種情況下,構(gòu)造函數(shù)初始化列表看起來(lái)似乎是用val初始化j,然后再用j來(lái)初始化i。然而i首先被初始化。這個(gè)初始化列表的效果是用尚未初始化的j值來(lái)初始化i!

            49、使用默認(rèn)構(gòu)造函數(shù)(P393)

            常犯的一個(gè)錯(cuò)誤是采用以下方式聲明一個(gè)用默認(rèn)構(gòu)造函數(shù)初始化的對(duì)象:

            Sales_item myobj();

            Sales_item myobj(); //ok: but defines a function, not an object

            if(myobj.same_isbn(Primer_3rd_ed)) // error: myobj is a function

            正確的方式應(yīng)該是去掉相應(yīng)的括號(hào):

            Sales_item myobj;

            或者

            Sales_item myobj = Sales_item();

            50、顯式或隱式初始化

            #include "stdafx.h"
            #include <iostream>
            using namespace std; 
            class MyClass
            {
            public :
                typedef int index_t;
                bool same_object(MyClass obj);
            
            public :
                MyClass(int default_index = 5)
                    :default_index(default_index),
                    m_name("default_name"){}
                MyClass::MyClass(std::string name);
            
            public :
                int default_index;
                std::string m_name;
            };
            
            MyClass::MyClass(std::string name)
                    :default_index(0), m_name(name){}
            
            bool MyClass::same_object(MyClass obj)
            {
                cout<<"m_name = "<<m_name.c_str()<<endl;
                cout<<"obj.m_name = "<<obj.m_name.c_str()<<endl;
                return strcmp(obj.m_name.c_str(), m_name.c_str()) == 0;
            }
            
            int _tmain(int argc, _TCHAR* argv[])
            {    
                MyClass obj;
            
                cout<<"explicit : "<<obj.same_object(MyClass("default_name"))<<endl;
                cout<<"implicit : "<<obj.same_object(string("default_name"))<<endl;
            
                return 0;
            }

            因?yàn)榫哂幸詓td::string為形參的構(gòu)造函數(shù),因此在調(diào)用需要MyClass對(duì)象的same_object成員函數(shù)時(shí),會(huì)自動(dòng)隱式調(diào)用該構(gòu)造函數(shù)構(gòu)建MyClass對(duì)象,用于操作。但生成的MyClass對(duì)象是臨時(shí)對(duì)象,在same_object函數(shù)調(diào)用完成后銷毀。如果為了避免產(chǎn)生隱式轉(zhuǎn)換可以使用explicit關(guān)鍵字來(lái)抑制由構(gòu)造函數(shù)定義的隱式轉(zhuǎn)換:

            explicit

            posted @ 2009-02-12 01:06 volnet 閱讀(1226) | 評(píng)論 (0)編輯 收藏

            僅列出標(biāo)題
            共9頁(yè): 1 2 3 4 5 6 7 8 9 
            特殊功能
             
            国产精品成人99久久久久| 狠狠88综合久久久久综合网| 狠狠色丁香久久综合婷婷| 久久综合九色综合97_久久久| 成人a毛片久久免费播放| 亚洲&#228;v永久无码精品天堂久久| 国产免费久久精品99re丫y| 久久免费的精品国产V∧| 国产精品久久久久久| 久久免费观看视频| 久久99精品国产麻豆宅宅| 久久久久久久亚洲精品| 久久综合88熟人妻| 久久婷婷五月综合成人D啪| 国产成人久久AV免费| 四虎影视久久久免费| 国产精品福利一区二区久久| 久久婷婷五月综合成人D啪| 久久久av波多野一区二区| 久久精品三级视频| 国产69精品久久久久777| 一级a性色生活片久久无| 色综合色天天久久婷婷基地| 亚洲国产欧美国产综合久久| 色婷婷久久综合中文久久一本| 久久精品国产99久久无毒不卡| 一本大道久久香蕉成人网| 99久久久久| 久久99中文字幕久久| 无码精品久久久久久人妻中字| 九九精品久久久久久噜噜| 久久国产热这里只有精品| 亚洲国产成人久久综合碰碰动漫3d| 亚洲AV乱码久久精品蜜桃| 亚洲&#228;v永久无码精品天堂久久| 91精品国产综合久久香蕉| 国内精品久久久久久久97牛牛| 欧美精品久久久久久久自慰| 亚洲日本va中文字幕久久| 亚洲AV无码成人网站久久精品大| 国产成人综合久久精品红|