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

            2018年11月6日

            #include<iconv.h> 
            #include <stdio.h>

            #include<iconv.h>
            using namespace std;
            int utf8togb2312(const char *sourcebuf,size_t sourcelen,char *destbuf,size_t destlen) {   

            iconv_t cd;   

            if( (cd = iconv_open("gb2312","utf-8")) ==0 )     

                  return -1;  

            memset(destbuf,0,destlen);   

            const char **source = &sourcebuf;   

            char **dest = &destbuf;
            if(-1 == iconv(cd,source,&sourcelen,dest,&destlen))     

                 return -1;   

            iconv_close(cd);   

            return 0;   

            }
            int gb2312toutf8(const char *sourcebuf,size_t sourcelen,char *destbuf,size_t destlen) {   

            iconv_t cd;   if( (cd = iconv_open("utf-8","gb2312")) ==0 )     

            return -1;   memset(destbuf,0,destlen);   

            const char **source = &sourcebuf;   

            char **dest = &destbuf;
              if(-1 == iconv(cd,source,&sourcelen,dest,&destlen))     

            return -1;   
            posted @ 2018-11-06 16:59 sheng 閱讀(337) | 評論 (0)編輯 收藏

            2016年8月26日

                 摘要: 轉載自http://blog.csdn.net/u010984552/article/details/51887108為什么需要線程池目前的大多數(shù)網(wǎng)絡服務器,包括Web服務器、Email服務器以及數(shù)據(jù)庫服務器等都具有一個共同點,就是單位時間內(nèi)必須處理數(shù)目巨大的連接請求,但處理時間卻相對較短。 傳 統(tǒng)多線程方案中我們采用的服務器模型則是一旦接受到請求之后,即創(chuàng)建一個新的線程,由該線程執(zhí)行任...  閱讀全文
            posted @ 2016-08-26 16:46 sheng 閱讀(399) | 評論 (0)編輯 收藏

            2016年8月17日


            摘自
            http://blog.csdn.net/hackbuteer1/article/details/7722667

            在 各種計算機體系結構中,對于字節(jié)、字等的存儲機制有所不同,因而引發(fā)了計算機 通信領 域中一個很重要的問題,即通信雙方交流的信息單元(比特、字節(jié)、字、雙字等等)應該以什么樣的順序進行傳送。如果不達成一致的規(guī)則,通信雙方將無法進行正 確的編/譯碼從而導致通信失敗。目前在各種體系的計算機中通常采用的字節(jié)存儲機制主要有兩種:Big-Endian和Little-Endian,下面先從字節(jié)序說起。
            一、什么是字節(jié)序
            字節(jié)序,顧名思義字節(jié)的順序,再多說兩句就是大于一個字節(jié)類型的數(shù)據(jù)在內(nèi)存中的存放順序(一個字節(jié)的數(shù)據(jù)當然就無需談順序的問題了)。其實大部分人在實際的開 發(fā)中都很少會直接和字節(jié)序打交道。唯有在跨平臺以及網(wǎng)絡程序中字節(jié)序才是一個應該被考慮的問題。

            在所有的介紹字節(jié)序的文章中都會提到字 節(jié)序分為兩類:Big-Endian和Little-Endian,引用標準的Big-Endian和Little-Endian的定義如下:
            a) Little-Endian就是低位字節(jié)排放在內(nèi)存的低地址端,高位字節(jié)排放在內(nèi)存的高地址端。
            b) Big-Endian就是高位字節(jié)排放在內(nèi)存的低地址端,低位字節(jié)排放在內(nèi)存的高地址端。
            c) 網(wǎng)絡字節(jié)序:TCP/IP各層協(xié)議將字節(jié)序定義為Big-Endian,因此TCP/IP協(xié)議中使用的字節(jié)序通常稱之為網(wǎng)絡字節(jié)序。

            1.1 什么是高/低地址端
            首先我們要知道C程序映像中內(nèi)存的空間布局情況:在《C專 家編程》中或者《Unix環(huán)境高級編程》中有關于內(nèi)存空間布局情況的說明,大致如下圖:
            ----------------------- 最高內(nèi)存地址 0xffffffff
            棧底

            棧頂

            -----------------------

            NULL (空洞)
            -----------------------

            -----------------------
            未初始 化的數(shù)據(jù)
            ----------------------- 統(tǒng)稱數(shù)據(jù)段
            初始化的數(shù)據(jù)
            -----------------------
            正 文段(代碼段)
            ----------------------- 最低內(nèi)存地址 0x00000000
            由圖可以看出,再內(nèi)存分布中,棧是向下增長的,而堆是向上增長的。
            以上圖為例如果我們在棧 上分配一個unsigned char buf[4],那么這個數(shù)組變量在棧上是如何布局的呢?看下圖:
            棧底 (高地址)
            ----------
            buf[3]
            buf[2]
            buf[1]
            buf[0]

            ----------
            棧頂 (低地址)
            其實,我們可以自己在編譯器里面創(chuàng)建一個數(shù)組,然后分別輸出數(shù)組種每個元素的地址,來驗證一下。
            1.2 什么是高/低字節(jié)
            現(xiàn)在我們弄清了高/低地址,接著考慮高/低字節(jié)。有些文章中稱低位字節(jié)為最低有效位,高位字節(jié)為最高有效位。如果我們有一個32位無符號整型0x12345678,那么高位是什么,低位又是什么呢? 其實很簡單。在十進制中我們都說靠左邊的是高位,靠右邊的是低位,在其他進制也是如此。就拿 0x12345678來說,從高位到低位的字節(jié)依次是0x12、0x34、0x56和0x78。
            高/低地址端和高/低字節(jié)都弄清了。我們再來回顧 一下Big-Endian和Little-Endian的定義,并用圖示說明兩種字節(jié)序:
            以unsigned int value = 0x12345678為例,分別看看在兩種字節(jié)序下其存儲情況,我們可以用unsigned char buf[4]來表示value:
            Big-Endian: 低地址存放高位,如下圖:
            棧底 (高地址)
            ---------------
            buf[3] (0x78) -- 低位
            buf[2] (0x56)
            buf[1] (0x34)
            buf[0] (0x12) -- 高位
            ---------------
            棧頂 (低地址)

            Little-Endian: 低地址存放低位,如下圖:
            棧底 (高地址)
            ---------------
            buf[3] (0x12) -- 高位
            buf[2] (0x34)
            buf[1] (0x56)
            buf[0] (0x78) -- 低位
            --------------
            棧 頂 (低地址)

            二、各種Endian
            2.1 Big-Endian
            計算機體系結構中一種描述多字節(jié)存儲順序的術語,在這種機制中最重要字節(jié)(MSB)存放在最低端的地址 上。采用這種機制的處理器有IBM3700系列、PDP-10、Mortolora微處理器系列和絕大多數(shù)的RISC處理器。
            +----------+
            | 0x34 |<-- 0x00000021
            +----------+
            | 0x12 |<-- 0x00000020
            +----------+
            圖 1:雙字節(jié)數(shù)0x1234以Big-Endian的方式存在起始地址0x00000020中

            在Big-Endian中,對于bit序列 中的序號編排方式如下(以雙字節(jié)數(shù)0x8B8A為例):
            bit 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
            +-----------------------------------------+
            val | 1 0 0 0 1 0 1 1 | 1 0 0 0 1 0 1 0 |
            +----------------------------------------+
            圖 2:Big-Endian的bit序列編碼方式
            2.2 Little-Endian
            計算機體系結構中 一種描述多字節(jié)存儲順序的術語,在這種機制中最不重要字節(jié)(LSB)存放在最低端的地址上。采用這種機制的處理器有PDP-11、VAX、Intel系列微處理器和一些網(wǎng)絡通信設備。該術語除了描述多字節(jié)存儲順序外還常常用來描述一個字節(jié)中各個比特的排放次序。

            +----------+
            | 0x12 |<-- 0x00000021
            +----------+
            | 0x34 |<-- 0x00000020
            +----------+

            圖3:雙字節(jié)數(shù)0x1234以Little-Endian的方式存在起始地址0x00000020中
             在 Little-Endian中,對于bit序列中的序號編排和Big-Endian剛好相反,其方式如下(以雙字節(jié)數(shù)0x8B8A為例):
            bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
            +-----------------------------------------+
            val | 1 0 0 0 1 0 1 1 | 1 0 0 0 1 0 1 0 |
            +-----------------------------------------+
            圖 4:Little-Endian的bit序列編碼方式
            注意:通常我們說的主機序(Host Order)就是遵循Little-Endian規(guī)則。所以當兩臺主機之間要通過TCP/IP協(xié)議進行通信的時候就需要調用相應的函數(shù)進行主機序 (Little-Endian)和網(wǎng)絡序(Big-Endian)的轉換。
            采用 Little-endian模式的CPU對操作數(shù)的存放方式是從低字節(jié)到高字節(jié),而Big-endian模式對操作數(shù)的存放方式是從高字節(jié)到低字節(jié)。 32bit寬的數(shù)0x12345678在Little-endian模式CPU內(nèi)存中的存放方式(假設從地址0x4000開始存放)為:
                                                      內(nèi)存地址     0x4000     0x4001     0x4002     0x4003
                                                      存放內(nèi)容     0x78        0x56        0x34         0x12
            而在Big- endian模式CPU內(nèi)存中的存放方式則為:
                                                      內(nèi)存地址     0x4000     0x4001     0x4002     0x4003
                                                      存放內(nèi)容     0x12         0x34        0x56         0x78
            具體的區(qū)別如下:


            三、Big-Endian和Little-Endian優(yōu)缺點
            Big-Endian優(yōu)點:靠首先提取高位字節(jié),你總是可以由看看在偏移位置為0的字節(jié)來確定這個數(shù)字是 正數(shù)還是負數(shù)。你不必知道這個數(shù)值有多長,或者你也不必過一些字節(jié)來看這個數(shù)值是否含有符號位。這個數(shù)值是以它們被打印出來的順序存放的,所以從二進制到十進制的函數(shù)特別有效。因而,對于不同要求的機器,在設計存取方式時就會不同。

            Little-Endian優(yōu)點:提取一個,兩個,四個或者更長字節(jié)數(shù)據(jù)的匯編指令以與其他所有格式相同的方式進行:首先在偏移地址為0的地方提取最低位的字節(jié),因為地址偏移和字節(jié)數(shù)是一對一的關系,多重精度的數(shù)學函數(shù)就相對地容易寫了。

            如果你增加數(shù)字的值,你可能在左邊增加數(shù)字(高位非指數(shù)函數(shù)需要更多的數(shù)字)。 因此, 經(jīng)常需要增加兩位數(shù)字并移動存儲器里所有Big-endian順序的數(shù)字,把所有數(shù)向右移,這會增加計算機的工作量。不過,使用Little- Endian的存儲器中不重要的字節(jié)可以存在它原來的位置,新的數(shù)可以存在它的右邊的高位地址里。這就意味著計算機中的某些計算可以變得更加簡單和快速。
            四、請寫一個C函數(shù),若處理器是Big_endian的,則返回0;若是Little_endian的,則返回1。
            1. int checkCPU(void)  
            2. {  
            3.     union  
            4.     {  
            5.         int a;  
            6.         char b;  
            7.     }c;  
            8.     c.a = 1;  
            9.     return (c.b == 1);  
            10. }  
            剖析:由于聯(lián)合體union的存放順序是所有成員都從低地址開始存放,利用該特性就可以輕松地獲得了CPU對內(nèi)存采用Little- endian還是Big-endian模式讀寫。
            說明:
            1  在c中,聯(lián)合體(共用體)的數(shù)據(jù)成員都是從低地址開始存放。
            2  若是小端模式,由低地址到高地址c.a存放為0x01 00 00 00,c.b被賦值為0x01;
              ————————————————————————————
               地址 0x00000000 0x00000001 0x00000002 0x00000003
               c.a  01         00         00         00
               c.b  01         00        
              ————————————————————————————  
            3  若是大端模式,由低地址到高地址c.a存放為0x00 00 00 01,c.b被賦值為0x0;
              ————————————————————————————
               地址 0x00000000 0x00000001 0x00000002 0x00000003
               c.a  00         00         00         01
               c.b  00         00                 
              ————————————————————————————  
            4  根據(jù)c.b的值的情況就可以判斷cpu的模式了。

            舉例,一個16進制數(shù)是 0x11 22 33,其存放的位置是
            地址0x3000 中存放11
            地址0x3001 中存放22
            地址0x3002 中存放33
            連起來就寫成地址0x3000-0x3002中存放了數(shù)據(jù)0x112233
            而這種存放和表示方式,正好符合大端。

            另外一個比較好理解的寫法如下:
            1. bool checkCPU()     // 如果是大端模式,返回真  
            2. {  
            3.     short int test = 0x1234;  
            4.   
            5.     if( *((char *)&test) == 0x12)     // 低地址存放高字節(jié)數(shù)據(jù)  
            6.         return true;  
            7.     else  
            8.         return false;  
            9. }  
            10.   
            11. int main(void)  
            12. {  
            13.     if( !checkCPU())  
            14.         cout<<"Little endian"<<endl;  
            15.     else  
            16.         cout<<"Big endian"<<endl;  
            17.   
            18.     return 0;  
            19. }  
            或者下面兩種寫法也是可以的
            1. int main(void)  
            2. {  
            3.     short int a = 0x1234;  
            4.     char *p = (char *)&a;  
            5.   
            6.     if( *p == 0x34)  
            7.         cout<<"Little endian"<<endl;  
            8.     else  
            9.         cout<<"Big endian"<<endl;  
            10.   
            11.     return 0;  
            12. }  
            13.   
            14. int main(void)  
            15. {  
            16.     short int a = 0x1234;  
            17.     char x0 , x1;  
            18.   
            19.     x0 = ((char *)&a)[0];  
            20.     x1 = ((char *)&a)[1];  
            21.   
            22.     if( x0 == 0x34)  
            23.         cout<<"Little endian"<<endl;  
            24.     else  
            25.         cout<<"Big endian"<<endl;  
            26.   
            27.     return 0;  
            28. }  
            posted @ 2016-08-17 14:21 sheng 閱讀(190) | 評論 (0)編輯 收藏

            2016年6月30日

                 摘要: C++ 虛函數(shù)表解析 陳皓http://blog.csdn.net/haoel  前言 C++中的虛函數(shù)的作用主要是實現(xiàn)了多態(tài)的機制。關于多態(tài),簡而言之就是用父類型別的指針指向其子類的實例,然后通過父類的指針調用實際子類的成員函數(shù)。這種技術可以讓父類的指針有“多種形態(tài)”,這是一種泛型技術。所謂泛型技術,說白了就是試圖使用不變...  閱讀全文
            posted @ 2016-06-30 15:36 sheng 閱讀(203) | 評論 (0)編輯 收藏

            2016年4月14日

            首先看看如下一個聲明:

             

            int* ( *( *fun )( int* ) )[10];

             

            這是一個會讓初學者感到頭暈目眩、感到恐懼的函數(shù)指針聲明。在熟練掌握C/C++的聲明語法之前,不學習一定的規(guī)則,想理解好這類復雜聲明是比較困難的。

             

            C/C++所有復雜的聲明結構,都是由各種聲明嵌套構成的。如何解讀復雜指針聲明?右左法則是一個很著名、很有效的方法。不過,右左法則其實并不是C/C++標準里面的內(nèi)容,它是從C/C++標準的聲明規(guī)定中歸納出來的方法。C/C++標準的聲明規(guī)則,是用來解決如何創(chuàng)建聲明的,而右左法則是用來解決如何辯識一個聲明的,從嵌套的角度看,兩者可以說是一個相反的過程。右左法則的英文原文是這樣說的:

             

            The right-left rule: Start reading the declaration from the innermost parentheses, go right, and then go left. When you encounter parentheses, the direction should be reversed. Once everything in the parentheses has been parsed, jump out of it. Continue till the whole declaration has been parsed.

             

             

            這段英文的翻譯如下:

             

            右左法則:首先從最里面的圓括號看起,然后往右看,再往左看。每當遇到圓括號時,就應該掉轉閱讀方向。一旦解析完圓括號里面所有的東西,就跳出圓括號。重復這個過程直到整個聲明解析完畢。

             

                筆者要對這個法則進行一個小小的修正,應該是從未定義的標識符開始閱讀,而不是從括號讀起,之所以是未定義的標識符,是因為一個聲明里面可能有多個標識符,但未定義的標識符只會有一個。

             

                現(xiàn)在通過一些例子來討論右左法則的應用,先從最簡單的開始,逐步加深:

             

            int (*func)(int *p);

             

            首先找到那個未定義的標識符,就是func,它的外面有一對圓括號,而且左邊是一個*號,這說明func是一個指針,然后跳出這個圓括號,先看右邊,也是一個圓括號,這說明(*func)是一個函數(shù),而func是一個指向這類函數(shù)的指針,就是一個函數(shù)指針,這類函數(shù)具有int*類型的形參,返回值類型是int

             

            int (*func)(int *p, int (*f)(int*));

             

            func被一對括號包含,且左邊有一個*號,說明func是一個指針,跳出括號,右邊也有個括號,那么func是一個指向函數(shù)的指針,這類函數(shù)具有int *int (*)(int*)這樣的形參,返回值為int類型。再來看一看func的形參int (*f)(int*),類似前面的解釋,f也是一個函數(shù)指針,指向的函數(shù)具有int*類型的形參,返回值為int

             

            int (*func[5])(int *p);

             

            func右邊是一個[]運算符,說明func是一個具有5個元素的數(shù)組,func的左邊有一個*,說明func的元素是指針,要注意這里的*不是修飾func的,而是修飾func[5]的,原因是[]運算符優(yōu)先級比*高,func先跟[]結合,因此*修飾的是func[5]。跳出這個括號,看右邊,也是一對圓括號,說明func數(shù)組的元素是函數(shù)類型的指針,它所指向的函數(shù)具有int*類型的形參,返回值類型為int

             

             

            int (*(*func)[5])(int *p);

             

            func被一個圓括號包含,左邊又有一個*,那么func是一個指針,跳出括號,右邊是一個[]運算符號,說明func是一個指向數(shù)組的指針,現(xiàn)在往左看,左邊有一個*號,說明這個數(shù)組的元素是指針,再跳出括號,右邊又有一個括號,說明這個數(shù)組的元素是指向函數(shù)的指針。總結一下,就是:func是一個指向數(shù)組的指針,這個數(shù)組的元素是函數(shù)指針,這些指針指向具有int*形參,返回值為int類型的函數(shù)。

             

            int (*(*func)(int *p))[5];

             

            func是一個函數(shù)指針,這類函數(shù)具有int*類型的形參,返回值是指向數(shù)組的指針,所指向的數(shù)組的元素是具有5int元素的數(shù)組。

             

            要注意有些復雜指針聲明是非法的,例如:

             

            int func(void) [5];

             

            func是一個返回值為具有5int元素的數(shù)組的函數(shù)。但C語言的函數(shù)返回值不能為數(shù)組,這是因為如果允許函數(shù)返回值為數(shù)組,那么接收這個數(shù)組的內(nèi)容的東西,也必須是一個數(shù)組,但C/C++語言的數(shù)組名是一個不可修改的左值,它不能直接被另一個數(shù)組的內(nèi)容修改,因此函數(shù)返回值不能為數(shù)組。

             

            int func[5](void);

             

            func是一個具有5個元素的數(shù)組,這個數(shù)組的元素都是函數(shù)。這也是非法的,因為數(shù)組的元素必須是對象,但函數(shù)不是對象,不能作為數(shù)組的元素。

             

            實際編程當中,需要聲明一個復雜指針時,如果把整個聲明寫成上面所示這些形式,將對可讀性帶來一定的損害,應該用typedef來對聲明逐層分解,增強可讀性。

             

            typedef是一種聲明,但它聲明的不是變量,也沒有創(chuàng)建新類型,而是某種類型的別名。typedef有很大的用途,對一個復雜聲明進行分解以增強可讀性是其作用之一。例如對于聲明:

             

            int (*(*func)(int *p))[5];

             

            可以這樣分解:

             

            typedef  int (*PARA)[5];

            typedef PARA (*func)(int *);

             

            這樣就容易看得多了。

             

            typedef的另一個作用,是作為基于對象編程的高層抽象手段。在ADT中,它可以用來在C/C++和現(xiàn)實世界的物件間建立關聯(lián),將這些物件抽象成C/C++的類型系統(tǒng)。在設計ADT的時候,我們常常聲明某個指針的別名,例如:

             

            typedef struct node * list;

             

            ADT的角度看,這個聲明是再自然不過的事情,可以用list來定義一個列表。但從C/C++語法的角度來看,它其實是不符合C/C++聲明語法的邏輯的,它暴力地將指針聲明符從指針聲明器中分離出來,這會造成一些異于人們閱讀習慣的現(xiàn)象,考慮下面代碼:

             

            const struct node *p1;

            typedef struct node *list;

            const list p2;

             

            p1類型是const struct node*,那么p2呢?如果你以為就是把list簡單“代入”p2,然后得出p2類型也是const struct node*的結果,就大錯特錯了。p2的類型其實是struct node * const p2,那個const限定的是p2,不是node。造成這一奇異現(xiàn)象的原因是指針聲明器被分割,標準中規(guī)定:

             

            6.7.5.1 Pointer declarators

             

            Semantics

             

             If in the declaration ‘‘T D1’, D1 has the form

             

            * type-qualifier-listopt D

             

            and the type specified for ident in the declaration ‘‘T D’’ is

             

            ‘‘derived-declarator-type-list T’’

             

            then the type specified for ident is

             

            ‘‘derived-declarator-type-list type-qualifier-list pointer to T’’

             

            For each type qualifier in the list, ident is a so-qualified pointer.

             

            指針的聲明器由指針聲明符*、可選的類型限定詞type-qualifier-listopt和標識符D組成,這三者在邏輯上是一個整體,構成一個完整的指針聲明器。這也是多個變量同列定義時指針聲明符必須緊跟標識符的原因,例如:

             

            int *p, q, *k;

             

            pk都是指針,但q不是,這是因為*p*k是一個整體指針聲明器,以表示聲明的是一個指針。編譯器會把指針聲明符左邊的類型包括其限定詞作為指針指向的實體的類型,右邊的限定詞限定被聲明的標識符。但現(xiàn)在typedef struct node *list硬生生把*從整個指針聲明器中分離出來,編譯器找不到*,會認為const list p2中的const是限定p2的,正因如此,p2的類型是node * const而不是const node*

             

            雖然typedef struct node* list不符合聲明語法的邏輯,但基于typedefADT中的重要作用以及信息隱藏的要求,我們應該讓用戶這樣使用list A,而不是list *A,因此在ADT的設計中仍應使用上述typedef語法,但需要注意其帶來的不利影響。

            posted @ 2016-04-14 13:49 sheng 閱讀(245) | 評論 (0)編輯 收藏
            C99中,結構中的最后一個元素允許是未知大小的數(shù)組,這就叫做柔性數(shù)組成員,但結構中的柔性數(shù)組成員前面必須至少一個其 他成員。柔性數(shù)組成員允許結構中包含一個大小可變的數(shù)組。sizeof返回的這種結構大小不包括柔性數(shù)組的內(nèi)存。包含柔性數(shù)組成員的結構用malloc ()函數(shù)進行內(nèi)存的動態(tài)分配,并且分配的內(nèi)存應該大于結構的大小,以適應柔性數(shù)組的預期大小。】 
            C語言大全,“柔性數(shù)組成員”

            【柔性數(shù)組結構成員
              C99中,結構中的最后一個元素允許是未知大小的數(shù)組,這就叫做柔性數(shù)組成員,但結構中的柔性數(shù)組成員前面必須至少一個其 他成員。柔性數(shù)組成員允許結構中包含一個大小可變的數(shù)組。sizeof返回的這種結構大小不包括柔性數(shù)組的內(nèi)存。包含柔性數(shù)組成員的結構用malloc ()函數(shù)進行內(nèi)存的動態(tài)分配,并且分配的內(nèi)存應該大于結構的大小,以適應柔性數(shù)組的預期大小。】 
            C語言大全,“柔性數(shù)組成員”

            看看 C99 標準中 靈活數(shù)組成員:

            結構體變長的妙用——0個元素的數(shù)組
            有時我們需要產(chǎn)生一個結構體,實現(xiàn)了一種可變長度的結構。如何來實現(xiàn)呢?
            看這個結構體的定義:
            typedef struct st_type
            {
            int nCnt;
            int item[0];
            }type_a;
            (有些編譯器會報錯無法編譯可以改成:)
            typedef struct st_type
            {
            int nCnt;
            int item[];
            }type_a;
            這樣我們就可以定義一個可變長的結構,用sizeof(type_a)得到的只有4,就是sizeof(nCnt)=sizeof(int)那

            個0個元素的數(shù)組沒有占用空間,而后我們可以進行變長操作了。
            C語言版:
            type_a *p = (type_a*)malloc(sizeof(type_a)+100*sizeof(int));
            C++語言版:
            type_a *p = (type_a*)new char[sizeof(type_a)+100*sizeof(int)];
            這樣我們就產(chǎn)生了一個長為100的type_a類型的東西用p->item[n]就能簡單地訪問可變長元素,原理十分簡單

            ,分配了比sizeof(type_a)多的內(nèi)存后int item[];就有了其意義了,它指向的是int nCnt;后面的內(nèi)容,是沒

            有內(nèi)存需要的,而在分配時多分配的內(nèi)存就可以由其來操控,是個十分好用的技巧。
            而釋放同樣簡單:
            C語言版:
            free(p);
            C++語言版:
            delete []p;
            其實這個叫靈活數(shù)組成員(fleible array member)C89不支持這種東西,C99把它作為一種特例加入了標準。但

            是,C99所支持的是incomplete type,而不是zero array,形同int item[0];這種形式是非法的,C99支持的

            形式是形同int item[];只不過有些編譯器把int item[0];作為非標準擴展來支持,而且在C99發(fā)布之前已經(jīng)有

            了這種非標準擴展了,C99發(fā)布之后,有些編譯器把兩者合而為一。
            下面是C99中的相關內(nèi)容:
            6.7.2.1 Structure and union specifiers

            As a special case, the last element of a structure with more than one named member may have 

            an incomplete array type; this is called a flexible array member. With two exceptions, the 

            flexible array member is ignored. First, the size of the structure shall be equal to the offset 

            of the last element of an otherwise identical structure that replaces the flexible array member 

            with an array of unspecified length.106) Second, when a . (or ->) operator has a left operand 

            that is (a pointer to) a structure with a flexible array member and the right operand names that 

            member, it behaves as if that member were replaced with the longest array (with the same element 

            type) that would not make the structure larger than the object being accessed; the offset of the 

            array shall remain that of the flexible array member, even if this would differ from that of the 

            replacement array. If this array would have no elements, it behaves as if it had one element but 

            the behavior is undefined if any attempt is made to access that element or to generate a pointer 

            one past it.
            例如在VC++6里使用兩者之一都能通過編譯并且完成操作,而會產(chǎn)生warning C4200: nonstandard extension 

            used : zero-sized array in struct/union的警告消息。
            而在DEVCPP里兩者同樣可以使用,并且不會有警告消息。
            posted @ 2016-04-14 11:14 sheng 閱讀(475) | 評論 (0)編輯 收藏
                 摘要: 值得推薦的C/C++框架和庫【本文系外部轉貼,原文地址:http://coolshell.info/c/c++/2014/12/13/c-open-project.htm】留作存檔下次造輪子前先看看現(xiàn)有的輪子吧值得學習的C語言開源項目- 1. Webbench Webbench是一個在linux下使用的非常簡單的網(wǎng)站壓測工具。它使用fork()模擬多個客戶端同時訪問我們設定的URL,測試...  閱讀全文
            posted @ 2016-04-14 10:03 sheng 閱讀(679) | 評論 (0)編輯 收藏
                 摘要: Eric S. Raymond<esr@thyrsus.com>目錄1. 誰該閱讀這篇文章2. 我為什么寫這篇文章3.對齊要求4.填充5.結構體對齊及填充6.結構體重排序7.難以處理的標量的情況8.可讀性和緩存局部性9.其他封裝的技術10.工具11.證明及例外12.版本履歷 1. 誰該閱讀這篇文章本文是關于削減C語言程序內(nèi)存占用空間的一項技術——為了減...  閱讀全文
            posted @ 2016-04-14 09:10 sheng 閱讀(337) | 評論 (0)編輯 收藏

            2013年4月5日

            從實現(xiàn)裝飾者模式中思考C++指針和引用的選擇

             

            最近在看設計模式的內(nèi)容,偶然間手癢就寫了一個“裝飾者”模式的一個實例。該實例來源于風雪漣漪的博客,我對它做了簡化。作為一個經(jīng)典的設計模式,本身并沒有太多要說的內(nèi)容。但是在我嘗試使用C++去實現(xiàn)這個模式的實例的時候,出現(xiàn)了一些看似無關緊要但是卻引人深思的問題。

            首先,我想簡單介紹一下這個實例的含義。實例的目的是希望通過裝飾器類對已有的蛋糕類進行裝飾補充,于是按照裝飾者模式的設計結構,有類似圖1的設計結構。

            1 裝飾者模式

            蛋糕類和裝飾器類都繼承于一個公共的基類,該基類聲明了一些公共接口。這里簡單的使用getName來返回當前蛋糕的名稱,而裝飾器類可以對該蛋糕的名稱進行修改補充。具體的蛋糕類都有自己的名稱,比如CheeseCake返回的是“奶油蛋糕”。如果使用了裝飾器類對該類進行裝飾的話,返回的名字就發(fā)生了的變化,比如“裝飾了花的奶油蛋糕”,這正是裝飾器類的功能。實現(xiàn)這個功能的關鍵在于裝飾器公共基類Decorator,它包含了一個Cake類型的成員cake。在定義裝飾器的時候我們可以傳遞給裝飾器一個已經(jīng)建立好的蛋糕對象,比如CheeseCake對象。由于CheeseCakeCake的子類,因此該對象可以被cake成員記錄下來。由于具體的裝飾器繼承于裝飾器基類Decorator,因此保護乘員cake可以被看到,又因為裝飾器本身也是繼承與Cake的,因此也擁有getName的接口,這樣在裝飾器類內(nèi)用getName調用cakegetName接口并添加額外的操作就能完成裝飾的目的。另外,裝飾器本身也是Cake的子類,因此裝飾后的裝飾器類對象同時也是一個具體的蛋糕對象,它可以被再次裝飾!這樣裝飾器類反映在我們腦海里的情境就是一個原本的蛋糕對象外邊包裹了一層層裝飾器對象。

            以上的說明如果還不夠清楚的話,下邊展示具體的實現(xiàn)代碼。這里就需要考慮cake成員的類型問題,一般使用指針類型可能更符合C++的編程習慣。因為使用對象不僅消耗空間,還在每次構造對象的時候進行對象的復制,這都不是我們愿意看到的。當然,使用引用或許更合理,因為按照平常的經(jīng)驗,很多使用C++指針的地方都可以用引用代替,有人甚至建議多使用引用少使用指針(當然我也承認C++引用也有很多好處~。不過,當你讀完本文或許你就不大這么認為了。首先,我們用Cake*pCake實現(xiàn)這個裝飾器類內(nèi)的成員,先具體了解一下這個代碼的具體內(nèi)容。

            按 Ctrl+C 復制代碼
            按 Ctrl+C 復制代碼

            從代碼中不難看出程序的輸出結構應該是“裝飾過花的裝飾過花的奶油蛋糕”,事實也的確如此!從裝飾器的使用格式來看FlowerDecorator(&FlowerDecorator(&CheeseCake()))倒也不至于十分麻煩。但是剛才討論過,如果能使用引用代替會許會更“舒服”,至少不用傳遞參數(shù)之前還要使用&獲取一下地址了~

            既然如此,我們把成員修改為引用格式的:

            復制代碼
            #pragma once
            #include <iostream>
            using namespace std;
            //Cake公共基類,提供裝飾者和被裝飾物的統(tǒng)一接口
            class Cake
            {
            public:
                virtual string getName()const=0;
            };

            //一個具體的蛋糕
            class CheeseCake:public Cake
            {
            public:
                virtual string getName()const
                {
                    return string("奶油蛋糕");
                }
            };

            //一個裝飾者基類
            class Decorator:public Cake
            {
            protected:
                Cake &pCake;
            public:
                Decorator(Cake&pc):pCake(pc){}
            };

            //一個具體的裝飾器
            class FlowerDecorator:public Decorator
            {
            public:
                FlowerDecorator(Cake&pc):Decorator(pc){}
                virtual string getName()const
                {
                    string decName="裝飾過花的";
                    decName+=pCake.getName();
                    return decName;
                }
            };
            int main()
            {
                cout<<
                    FlowerDecorator(
                        FlowerDecorator(
                            CheeseCake()
                    ))
                    .getName().c_str()
                    <<endl;
                return 0;
            }
            復制代碼

            修改后的代碼看起來的確更“順眼了”。因為調用的時候我們不用再寫那個看著別扭的取地址運算符了,然后我們滿懷欣喜的執(zhí)行了程序,輸出結果為:“裝飾過花的奶油蛋糕”!你我的第一反應八成是覺得忘了多修飾一次了,但是我們認真的檢查代碼,發(fā)現(xiàn)的確一切都是符合邏輯的……

            上邊做了這么多鋪墊就是為了引出這個奇怪的問題,我其實也被該問題困惑了很久。稍有編程經(jīng)驗的人都會跟蹤調試這些構造函數(shù)的執(zhí)行過程,結果發(fā)現(xiàn)FlowerDecorator只被執(zhí)行了一次,因此少輸出一次“裝飾過花的”不足為奇。但是你我肯定好奇為什么會少輸出一次呢?

            再次再次的檢查代碼、調試、跟蹤,或許你會像發(fā)現(xiàn)新大陸一樣發(fā)現(xiàn)了一個隱藏的問題:第二次構造FlowerDecorator時調用的是復制構造函數(shù),而不是定義好的構造函數(shù)(雖然子類FlowerDecoratorCake的子類,但是編譯器會自動最佳匹配函數(shù)參數(shù)類型)!由于復制構造函數(shù)值原模原樣的拷貝出一個對象,所以只能完成一次裝飾器裝飾。非常完美的解釋!因此我們可以自己重寫復制構造函數(shù)來完成我們的裝飾功能,這里先忽略原本的對象復制功能了。編譯器為我們生成的復制構造函數(shù)應該是:

            FlowerDecorator(const FlowerDecorator&pc):Decorator(pc.pCake){}

            而我們應該將參數(shù)看作一個Cake對象進行裝飾,因此修改為:

            FlowerDecorator(const FlowerDecorator&pc):Decorator(const_cast<FlowerDecorator&>(pc)){}

            同樣,由于構造函數(shù)初始化了基類,所以基類的復制構造也需要重寫:

            Decorator(const Decorator&pc):pCake(const_cast<Decorator&>(pc)){}

            即使傳遞的參數(shù)是FlowerDecorator對象和CakeDecorator不是一個類型,但是編譯器或許默認的匹配繼承層次最近的類型!然后我們按照這樣要求重寫了代碼,執(zhí)行了程序,在期待結果的那一刻看到的是“裝飾過花的奶油蛋糕”……或許此時的你都會感到灰心,但是你還是依然的堅強的按下了F5單步跟蹤,結果你發(fā)現(xiàn)拷貝構造函數(shù)并沒有被調用!難道以上的假設都錯了嗎?我可以確定的告訴讀者,我們以上的假設都是正確的。

            最終我也是沒有辦法,去StackOverFlow上求助,綜合回答者的討論,我終于把問題的原因鎖定了——編譯器優(yōu)化!我覺得用一個最簡單的例子來說明這個問題再合適不過了:

            復制代碼
            class A
            {
            public:
                A(int)
                {
                    cout<<"構造\n";
                }
                A(const A&)
                {
                    cout<<"拷貝\n";
                }
            };

            int main()
            {
                A(0);
                cout<<"------------------------\n";
                A(A(0));
                cout<<"------------------------\n";
                A(A(A(0)));
                cout<<"------------------------\n";
                A(A(A(A(0))));
                cout<<"------------------------\n";
                A(A(A(A(A(0)))));
                cout<<"------------------------\n";
                return 0;
            }
            復制代碼

            這個簡單的例子結果或許大家都很明白,但是你親自測試一下就可能要懷疑自己的判斷能力了,程序輸出:

            是不是有點世界觀被顛覆的感覺?需要聲明一下,這個是Visual Studio 2010下的測試結果,因為這個程序的輸出的確和編譯器相關!為了確認我用gcc-4.4.3測試了該段代碼,輸出結果為:

            看來,還是gcc優(yōu)化的比較徹底。因此我們可以得出結論,類似這種無名對象的構造(有名的是按照規(guī)矩來的),調用多少次構造函數(shù)要看編譯器的“脾氣”了。到這里,不知道你對引用參數(shù)的感覺如何?

            討論到這,或許有人說和本來要討論的話題離得太遠了。其實并不是,佛家說:“今日之果皆來自昨日之因”,一切的一切都是由于我們使用了本以為毫無懸念的引用導致的!如果使用指針就不可能發(fā)生和拷貝構造函數(shù)沖突的問題,也不會導致編譯器優(yōu)化的問題!回視本文剛開始舉的例子和該文的主題,或許我們應該清楚有時候的確要好好區(qū)分一下指針和引用的差別了,當然本文也是從一個實踐的例子中去發(fā)現(xiàn)和挖掘這一點。

            posted @ 2013-04-05 11:27 sheng 閱讀(207) | 評論 (0)編輯 收藏

            2013年3月1日

             


            STL跨平臺調用會出現(xiàn)很多異常,你可以試試.

            STL使用模板生成,當我們使用模板的時候,每一個EXE,和DLL都在編譯器產(chǎn)生了自己的代碼,導致模板所使用的靜態(tài)成員不同步,所以出現(xiàn)數(shù)據(jù)傳遞的各種問題,下面是詳細解釋。

            原因分析:
            一句話-----如果任何STL類使用了靜態(tài)變量(無論是直接還是間接使用),那么就不要再寫出跨執(zhí)行單元訪問它的代碼。 除非你能夠確定兩個動態(tài)庫使用的都是同樣的STL實現(xiàn),比如都使用VC同一版本的STL,編譯選項也一樣。強烈建議,不要在動態(tài)庫接口中傳遞STL容器!!

            STL不一定不能在DLL間傳遞,但你必須徹底搞懂它的內(nèi)部實現(xiàn),并懂得為何會出問題。
            微軟的解釋:
            http://support.microsoft.com/default.aspx?scid=kb%3ben-us%3b172396
            微軟給的解決辦法:
            http://support.microsoft.com/default.aspx?scid=kb%3ben-us%3b168958

            1、微軟的解釋:
            大部分C++標準庫里提供的類直接或間接地使用了靜態(tài)變量。由于這些類是通過模板擴展而來的,因此每個可執(zhí)行映像(通常是.dll或.exe文件)就會存在一份只屬于自己的、給定類的靜態(tài)數(shù)據(jù)成員。當一個需要訪問這些靜態(tài)成員的類方法執(zhí)行時,它使用的是“這個方法的代碼當前所在的那份可執(zhí)行映像”里的靜態(tài)成員變量。由于兩份可執(zhí)行映像各自的靜態(tài)數(shù)據(jù)成員并未同步,這個行為就可能導致訪問違例,或者數(shù)據(jù)看起來似乎丟失或被破壞了。

            可能不太好懂,我舉個例子:假如類A<T>有個靜態(tài)變量m_s,那么當1.exe使用了2.dll中提供的某個A<int>對象時,由于模板擴展機制,1.exe和2.dll中會分別存在自己的一份類靜態(tài)變量A<int>.m_s。
            這樣,假如1.exe中從2.dll中取得了一個的類A<int>的實例對象a,那么當在1.exe中直接訪問a.m_s時,其實訪問的是 1.exe中的對應拷貝(正確情況應該是訪問了2.dll中的a.m_s)。這樣就可能導致非法訪問、應當改變的數(shù)據(jù)沒有改變、不應改變的數(shù)據(jù)被錯誤地更改等異常情形。

            原文:
            Most classes in the Standard C++ Libraries use static data members directly or indirectly. Since these classes are generated through template instantiation, each executable image (usually with DLL or EXE file name extensions) will contain its own copy of the static data member for a given class. When a method of the class that requires the static data member is executed, it uses the static data member in the executable image in which the method code resides. Since the static data members in the executable images are not in sync, this action could result in an access violation or data may appear to be lost or corrupted.

            1、保證資源的分配/刪除操作對等并處于同一個執(zhí)行單元;
               比如,可以把這些操作(包括構造/析構函數(shù)、某些容器自動擴容{這個需要特別注意}時的內(nèi)存再分配等)隱藏到接口函數(shù)里面。換句話說:盡量不要直接從dll中輸出stl對象;如果一定要輸出,給它加上一層包裝,然后輸出這個包裝接口而不是原始接口。

            2、保證所有的執(zhí)行單元使用同樣版本的STL運行庫。
               比如,全部使用release庫或debug庫,否則兩個執(zhí)行單元擴展出來的STL類的內(nèi)存布局就可能會不一樣。

            只要記住關鍵就是:如果任何STL類使用了靜態(tài)變量(無論是直接還是間接使用),那么就不要再寫出跨執(zhí)行單元訪問它的代碼。

            解決方法:
            1. 一個可以考慮的方案
            比如有兩個動態(tài)庫L1和L2,L2需要修改L1中的一個map,那么我在L1中設置如下接口
            int modify_map(int key, int new_value);
            如果需要指定“某一個map”,則可以考慮實現(xiàn)一種類似于句柄的方式,比如可以傳遞一個DWORD
            不過這個DWORD放的是一個地址

            那么modify_map就可以這樣實現(xiàn):
            int modify_map(DWORD map_handle, int key, int new_value)
            {
                std::map<int, int>& themap = *(std::map<int, int>*)map_handle;
                themap[key] = new_value;
            }

            map_handle的值也首先由L1“告訴”L2:
            DWORD get_map_handle();

            L2可以這樣調用:
            DWORD h = get_map_handle();
            modify_map(h, 1, 2);

            2. 加入一個額外的層,就可以解決問題。所以,你需要將你的Map包裝在dll內(nèi)部,而不是讓它出現(xiàn)在接口當中。動態(tài)庫的接口越簡單越好,不好去傳太過復雜的東東是至理名言:)

             

            在動態(tài)連接庫開發(fā)中要特別注意內(nèi)存的分配與釋放問題,稍不注意,極可能造成內(nèi)存泄漏,從而訪問出錯。例如在某DLL中存在這樣一段代碼:

            extent "C" __declspec(dllexport) 
            void ExtractFileName( const std::string& path //!< Input path and filename.
            , std::string& fname //!< Extracted filename with extension.
            )
            {
            std::string::size_type startPos = path.find_last_of('\\');
            fname.assign(path.begin() startPos 1, path.end() );
            }

            在DLL中使用STL對象std::string,并且在其中改變std::string的內(nèi)容,即發(fā)生了內(nèi)存的重分配問題,若在EXE中調用該函數(shù)會出現(xiàn)內(nèi)存訪問問題。主要是:因為DLL和EXE的內(nèi)存分配方式不同,DLL中的分配的內(nèi)存不能在EXE中正確釋放掉。

            解決這一問題的途徑如下:
            一般情況下:構建DLL必須遵循誰分配就由誰釋放的原則,例如COM的解決方案(利用引用計數(shù)),對象的創(chuàng)建(QueryInterface)與釋放均在COM組件內(nèi)部完成。在純C 環(huán)境下,可以很容易的實現(xiàn)類似方案。


            在應用STL的情況下,很難使用上述方案來解決,因此必須另辟蹊徑,途徑有二:
            1、自己寫內(nèi)存分配器替代STL中的默認分配器。
            2、使用STLport替代系統(tǒng)的標準庫。

            其實,上述問題在VC7及以后版本中,已得到解決,注意DLL工程和調用的工程一定要使用多線程DLL庫,就不會發(fā)生內(nèi)存訪問問題。

             

             

            一個很奇怪的問題:DLL中使用std::string作為參數(shù)結果出錯

            這段時間,在工程中將一些功能封裝成動態(tài)庫,需要使用動態(tài)庫接口的時候.使用了STL的一些類型作為參數(shù).

            比方string,vector,list.但是在使用接口的時候.
            1. class exportClass
            2. {
            3.      bool dll_funcation(string &str);
            4. };
            復制代碼
            //上面這個類只是一個形式,具體內(nèi)容不寫出來了.這個類被導出

            當我在使用這個庫的時候.這樣寫代碼:
            1. string str="":
            2. exportClass tmp;
            3. tmp.dll_function(str);
            復制代碼
            這個函數(shù)能成功調用.但是在函數(shù)里面會給這個數(shù)組附值.如果字符串太長,就會出錯.函數(shù)調用能成功,但是一旦str資源需要釋放的時候,資源就不能釋放了,提示釋放了錯誤的內(nèi)存空間.

            一點一點取掉這個函數(shù)的代碼.最后就剩下

            str="qadasdasdasdsafsafas";

            還是出錯誤.

            如果改成很短的字符串,就不會出錯誤.
            在這個時候,只能嘗試認為是字符串的空間太小

            最終我修改成這樣,錯誤消失了.希望錯誤真的是這個引起的
            1. string str="":

            2. str.resize(1000);

            3. exportClass tmp;

            4. tmp.dll_function(str);

             

            今天寫程序的時候要給一個模塊的dll傳遞一個參數(shù),由于參數(shù)數(shù)量是可變的,因此設計成了vector<string>類型,但調試過程中發(fā)現(xiàn)在exe中的參數(shù)傳遞到dll中的函數(shù)后,vector變成空的,改成傳引用類型后,vector竟然變得很大,并且是無意義的參數(shù)。

            對于這個問題,兩種辦法:

            1.傳遞vector指針

            2.傳遞const vector<TYPE>。

            究其原因:

            是因為vector在exe和dll之間傳遞的時候,由于在dll內(nèi)可能對vector插入數(shù)據(jù),而這段內(nèi)存是在dll里面分配的,exe無法知道如何釋放內(nèi)存,從而導致問題。而改成const類型后,編譯器便知道dll里不會改變vector,從而不會出錯。

            或者可以說這是"cross-DLL problem."(This problem crops up when an object is created using new in one dynamically linked library (DLL) but is deleted in a different DLL)的一種吧。

            對于STL,在DLL中使用的時候,往往存在這些問題,在網(wǎng)絡上搜集了下,這些都是要平時使用STL的時候注意的。

            ***************************************************************************************************************

            引用http://www.hellocpp.net/Articles/Article/714.aspx

            當template 遭遇到dynamic link 時候, 很多時候卻是一場惡夢.
            現(xiàn)在來說說一部分我已經(jīng)碰到過的問題. 問題主要集中在內(nèi)存分配上.
            1> 
                  拿STL來說, 自己寫模板的時候,很難免就用到stl. stl的代碼都在頭文件里. 那么表示著內(nèi)存分配的代碼.只有包含了它的cpp 編譯的時候才會被決定是使用什么樣的內(nèi)存分配代碼. 考慮一下: 當你聲明了一個vector<> . 并把這個vector<>交給一個 dll里的代碼來用. 用完后, 在你的程序里被釋放了.    那么如果你 在dll里往vector里insert了一些東西. 那么這個時候insert 發(fā)生的內(nèi)存分配的代碼是屬于dll的. 你不知道這個dll的內(nèi)存分配是什么. 是分配在哪里的. 而這個時候.釋放那促的動作卻不在dll里.....同時. 你甚至無法保證編譯dll的那個家伙使用的stl版本和你是完全一樣的..>
                  如此說來, 程序crash掉是天經(jīng)地義的.... 
                  對策: 千萬別別把你的stl 容器,模板容器在 dll 間傳來傳去 . 記住string也是....

            2> 
                 你在dll的某個類里聲明了一個vector之類的容器. 而沒有顯式的寫這個類的構造和析構函數(shù). 那么問題又來了.
                 你這個類肯定有操作這vector的函數(shù). 那么這些函數(shù)會讓vecoter<>生成代碼. 這些代碼在這個dll里都是一致的. 但是別忘了.你沒有寫析構函數(shù)...... 如果這個時候, 別人在外面聲明了一個這樣的類.然后調用這個類的函數(shù)操作了這個vector( 當然使用者并不知道什么時候操作了vector) . 它用完了這個類以后. 類被釋放掉了. 編譯器很負責的為它生成了一份析構函數(shù)的代碼...... 聽好了.這份代碼并不是在 dll里 ... . 事情于是又和1>里的一樣了.... crash ......(可能還會伴隨著迷茫.....)
                 對策: 記得dll里每個類,哪怕式構造析構函數(shù)式空的. 也要寫到cpp里去. 什么都不寫也式很糟糕的.....同時,更要把任何和內(nèi)存操作有關的函數(shù)寫到 .cpp 里...

            3> 
                以上兩個問題似乎都是比較容易的-----只要把代碼都寫到cpp里去, 不要用stl容器傳來傳去就可以了.
               那么第三個問題就要麻煩的多.
               如果你自己寫了一個模板, 這個模板用了stl 容器..........
               這個時候你該怎么辦呢?
             顯然你無法把和內(nèi)存分配相關的函數(shù)都寫到.cpp里去 . template的代碼都必須放到header file里.....
               對策: 解決這個問題的基本做法是做一個stl 內(nèi)存分配器 , 強制把這個模板里和內(nèi)存分配相關的放到一個.cpp里去.這個時候編譯這個cpp就會把內(nèi)存分配代碼固定在一個地方: 要么是dll. 要么是exe里...

            模板+動態(tài)鏈接庫的使用問題還很多. 要千萬留心這個陷阱遍地的東西啊

            ***************************************************************************************************************************

            微軟關于這類問題的解釋:

            You may experience an access violation when you access an STL object through a pointer or reference in a different DLL or EXE

            http://support.microsoft.com/default.aspx?scid=KB;en-us;q172396

            How to export an instantiation of a Standard Template Library (STL) class and a class that contains a data member that is an STL object

            http://support.microsoft.com/default.aspx?scid=KB;en-us;q168958

             

             

             

            總結:

            字符串參數(shù)用char*,Vector用char**,

            動態(tài)內(nèi)存要牢記誰申請誰釋放的原則。
             
            posted @ 2013-03-01 13:58 sheng 閱讀(6712) | 評論 (0)編輯 收藏
            僅列出標題  下一頁

            導航

            <2011年12月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            統(tǒng)計

            常用鏈接

            留言簿(1)

            隨筆檔案

            收藏夾

            同行

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            久久久婷婷五月亚洲97号色 | 91久久成人免费| 久久国产精品无码网站| 四虎国产精品免费久久| 久久综合狠狠综合久久综合88| 四虎国产精品免费久久久| 欧美日韩精品久久久免费观看| 浪潮AV色综合久久天堂| 久久久精品国产Sm最大网站| 亚洲AV无码久久精品狠狠爱浪潮| 思思久久99热只有频精品66| 久久99精品国产麻豆| 婷婷久久综合九色综合绿巨人| 久久人人爽人人爽人人AV东京热| 精品久久人人妻人人做精品 | 99久久精品午夜一区二区| 无码人妻少妇久久中文字幕| 久久96国产精品久久久| 久久久久久综合网天天| 久久久青草青青国产亚洲免观| 国内精品久久久久影院优| 久久www免费人成看片| 欧美一级久久久久久久大| 日本免费一区二区久久人人澡| 日韩av无码久久精品免费| 国产一区二区久久久| 亚洲AⅤ优女AV综合久久久| 国产成人精品久久亚洲| 久久99精品国产麻豆宅宅| 国产精品免费看久久久| 久久国产精品一国产精品金尊| 亚洲综合伊人久久综合| 中文字幕久久精品无码| 人妻无码αv中文字幕久久琪琪布| 久久久精品日本一区二区三区| 国产高潮国产高潮久久久91 | 久久无码专区国产精品发布| 色欲综合久久躁天天躁| 合区精品久久久中文字幕一区| 久久综合久久性久99毛片| 国产精品99久久不卡|