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

            積木

            No sub title

              C++博客 :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
              140 Posts :: 1 Stories :: 11 Comments :: 0 Trackbacks

            常用鏈接

            留言簿(1)

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

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            #

            原文轉(zhuǎn)載自:http://blog.csdn.net/leishiwei/article/details/4009307

            看完下面這篇文章,即可明白為什么在使用lua時(shí),需要對所包含的頭文件添加:extern "C"這樣的符號來括起來。
            extern "C"
            {
                #include "lua.h"
                #include "lualib.h"
                #include "luaxlib.h"
            }

            Lua編譯要考慮extern “C”

            分類: 游戲腳本 219人閱讀 評論(1) 收藏 舉報(bào)

             (轉(zhuǎn) 七星重劍)
            C++項(xiàng)目要到了如Lua這種純C寫成的庫時(shí),如果鏈接不過,就考慮是包含頭文件時(shí)沒加extern “C”。
            #ifdef __cplusplus
            extern "C" {
            #endif
                #include "lualib.h"
                #include "lauxlib.h"
            #ifdef __cplusplus
            }
            #endif
              
            時(shí)常在cpp的代碼之中看到這樣的代碼:
            #ifdef __cplusplus
            extern "C" {
            #endif
            //一段代碼
            #ifdef __cplusplus
            }
            #endif
              這樣的代碼到底是什么意思呢?首先,__cplusplus是cpp中的自定義宏,那么定義了這個(gè)宏的話表示這是一段cpp的代碼,也就是說,上面的代碼的含義是:如果這是一段cpp的代碼,那么加入extern "C"{和}處理其中的代碼。
              要明白為何使用extern "C",還得從cpp中對函數(shù)的重載處理開始說起。在c++中,為了支持重載機(jī)制,在編譯生成的匯編碼中,要對函數(shù)的名字進(jìn)行一些處理,加入比如函數(shù)的返回類型等等.而在C中,只是簡單的函數(shù)名字而已,不會加入其他的信息.也就是說:C++和C對產(chǎn)生的函數(shù)名字的處理是不一樣的.
              比如下面的一段簡單的函數(shù),我們看看加入和不加入extern "C"產(chǎn)生的匯編代碼都有哪些變化:
            int f(void)
            {
            return 1;
            }
              在加入extern "C"的時(shí)候產(chǎn)生的匯編代碼是:
            .file "test.cxx"
            .text
            .align 2
            .globl _f
            .def _f; .scl 2; .type 32; .endef
            _f:
            pushl %ebp
            movl %esp, %ebp
            movl $1, %eax
            popl %ebp
            ret
              但是不加入了extern "C"之后
            .file "test.cxx"
            .text
            .align 2
            .globl __Z1fv
            .def __Z1fv; .scl 2; .type 32; .endef
            __Z1fv:
            pushl %ebp
            movl %esp, %ebp
            movl $1, %eax
            popl %ebp
            ret
              兩段匯編代碼同樣都是使用gcc -S命令產(chǎn)生的,所有的地方都是一樣的,唯獨(dú)是產(chǎn)生的函數(shù)名,一個(gè)是_f,一個(gè)是__Z1fv。
              明白了加入與不加入extern "C"之后對函數(shù)名稱產(chǎn)生的影響,我們繼續(xù)我們的討論:為什么需要使用extern "C"呢?C++之父在設(shè)計(jì)C++之時(shí),考慮到當(dāng)時(shí)已經(jīng)存在了大量的C代碼,為了支持原來的C代碼和已經(jīng)寫好C庫,需要在C++中盡可能的支持C,而extern "C"就是其中的一個(gè)策略。
              試想這樣的情況:一個(gè)庫文件已經(jīng)用C寫好了而且運(yùn)行得很良好,這個(gè)時(shí)候我們需要使用這個(gè)庫文件,但是我們需要使用C++來寫這個(gè)新的代碼。如果這個(gè)代碼使用的是C++的方式鏈接這個(gè)C庫文件的話,那么就會出現(xiàn)鏈接錯(cuò)誤.我們來看一段代碼:首先,我們使用C的處理方式來寫一個(gè)函數(shù),也就是說假設(shè)這個(gè)函數(shù)當(dāng)時(shí)是用C寫成的:
            //f1.c
            extern "C"
            {
            void f1()
            {
            return;
            }
            }
              編譯命令是:gcc -c f1.c -o f1.o 產(chǎn)生了一個(gè)叫f1.o的庫文件。再寫一段代碼調(diào)用這個(gè)f1函數(shù):
            // test.cxx
            //這個(gè)extern表示f1函數(shù)在別的地方定義,這樣可以通過
            //編譯,但是鏈接的時(shí)候還是需要
            //鏈接上原來的庫文件.
            extern void f1();
            int main()
            {
            f1();
            return 0;
            }
              通過gcc -c test.cxx -o test.o 產(chǎn)生一個(gè)叫test.o的文件。然后,我們使用gcc test.o f1.o來鏈接兩個(gè)文件,可是出錯(cuò)了,錯(cuò)誤的提示是:
            test.o(.text + 0x1f):test.cxx: undefine reference to 'f1()'
              也就是說,在編譯test.cxx的時(shí)候編譯器是使用C++的方式來處理f1()函數(shù)的,但是實(shí)際上鏈接的庫文件卻是用C的方式來處理函數(shù)的,所以就會出現(xiàn)鏈接過不去的錯(cuò)誤:因?yàn)殒溄悠髡也坏胶瘮?shù)。
              因此,為了在C++代碼中調(diào)用用C寫成的庫文件,就需要用extern "C"來告訴編譯器:這是一個(gè)用C寫成的庫文件,請用C的方式來鏈接它們。
              比如,現(xiàn)在我們有了一個(gè)C庫文件,它的頭文件是f.h,產(chǎn)生的lib文件是f.lib,那么我們?nèi)绻贑++中使用這個(gè)庫文件,我們需要這樣寫:
            extern "C"
            {
            #include "f.h"
            }
              回到上面的問題,如果要改正鏈接錯(cuò)誤,我們需要這樣子改寫test.cxx:
            extern "C"
            {
            extern void f1();
            }
            int main()
            {
            f1();
            return 0;
            }
              重新編譯并且鏈接就可以過去了.
              總結(jié)
              C和C++對函數(shù)的處理方式是不同的.extern "C"是使C++能夠調(diào)用C寫作的庫文件的一個(gè)手段,如果要對編譯器提示使用C的方式來處理函數(shù)的話,那么就要使用extern "C"來說明。

            posted @ 2012-12-03 10:28 Jacc.Kim 閱讀(548) | 評論 (0)編輯 收藏

            1) 正如書中所述,stl所述的heap都是max-heap。即:父節(jié)點(diǎn)的“值”[注釋1],永遠(yuǎn)是 >= 其子節(jié)點(diǎn)的值。
            2) 正如書中所述,stl所述的heap不歸屬于容器。因?yàn)樗且唤M算法。這些算法的實(shí)現(xiàn)原理,在此[注釋2],是以一棵完全二叉樹來設(shè)計(jì)的。
            3) 以下對各個(gè)max-heap接口算法的小結(jié):

            a) make_heap()
            說明:顧名思義,該接口就是用來“創(chuàng)建”一個(gè)heap的。是對原有的一堆任意存放的數(shù)據(jù),按照第一點(diǎn)所述的規(guī)則,進(jìn)行“排列”(注意:不是排序)。
            示例(來自書中例子,抄出來,經(jīng)常看,印象會更深刻。在此,我們重在理解算法與掌握運(yùn)用):
            int ai[9] = {0, 1, 2, 3, 4, 8, 9, 3, 5};
            vector<int> ivec(ia, ia + 9);
            make_heap(ivec.begin(), ivec.end());//調(diào)用后,ivec中的數(shù)據(jù)的排列將改變掉,并且已經(jīng)是按max-heap的結(jié)構(gòu)存儲的。
            for (int i = 0; i < ivec.size(); i++)
                cout << ivec[i] << ' ';  // 9 5 8 3 4 0 2 3 1
            cout << endl;

            b) push_heap()
            說明:將新push_back()到ivec的末尾元素按照max-heap的要求規(guī)則,進(jìn)行位置調(diào)整。使得新的整個(gè)ivec中的元素排列規(guī)則符合max-heap的規(guī)則要求。
            注意:
                1) push_heap()的操作,一定都是針對最末尾的那個(gè)元素,對它的位置按照max-heap的要求,進(jìn)行重新調(diào)整的。
                2) 執(zhí)行push_heap()操作前,一定一定要保證除了最末尾的那個(gè)元素外,前面的元素的排列規(guī)則一定都滿足max-heap()的規(guī)則存放的。
            示例:
            ivec.push_back(7);
            push_heap(ivec.begin(), ivec.end());
            for (int i = 0; i < ivec.size(); i++)
                cout << ivec[i] << ' '; // 9 7 8 3 5 0 2 3 1 4
            cout << endl;

            c) pop_heap()
            說明:該接口意即:要從整個(gè)heap中,取出元素。但這里取出的一定是“值”最大的那個(gè)元素。而不是像vector或list等那樣,可以取出任意位置的元素。
            注意:
                1) 調(diào)用該接口“取出”元素后,其實(shí)該元素(即:“值”最大的那個(gè)元素)并未真正被取出來,而是將該元素放到了ivec的最末尾位置。(也正是因此,如果對整個(gè)ivec進(jìn)行多次的pop_heap()操作,即可完成ivec的排序功能)
                2) 正如 注意1) 所述的,則在pop_heap()后,ivec除了最末尾的那個(gè)元素外,前面的元素仍然是保持著max-heap的規(guī)則存儲的。
            示例:
            pop_heap(ivec.begin(), ivec.end());
            cout << ivec.back() << endl; // 9. return but not remove.
            ivec.pop_back(); // remove last elem and no return;

            d) sort_heap()
            說明:顧名思義,是對一個(gè)heap進(jìn)行排序。
            注意:
                  1) 排序后的“heap"(即:原始的heap)將不復(fù)存在(理由很簡單:排序后,原h(huán)eap中的元素的存儲規(guī)則不符合max-heap的規(guī)則,因此排序后的,就不能再稱為heap)
            示例:
            sort_heap(ivec.begin(), ivec.end());
            for (int i = 0; i < ivec.size(); i++)
                cout << ivec[i] << ' '; // 0 1 2 3 3 4 5 7 8
            cout << endl;

            補(bǔ)充:max-heap的隱式表達(dá)式的push_heap()與pop_heap()操作時(shí)間都只有:O(logN)。一種算是比較居中的,還算不錯(cuò)的時(shí)間性能參考值。

            最后再說兩點(diǎn):
               1) 只要深刻理解了以上算法與接口的使用,對實(shí)際項(xiàng)目的動作,個(gè)人認(rèn)為,是很有價(jià)值的。另外,理解了heap的原理,則我們也十分容易priority queue的實(shí)現(xiàn)細(xì)節(jié)。
               2) 對知識的掌握,還是重在理解。

            以上表述有誤之處,還望大伙多多指正啊。。:)

            [注釋1]:此處的值:我們可以當(dāng)它是節(jié)點(diǎn)本身的值,也可以當(dāng)它是某種權(quán)值。依自己使用需要而定。
            [注釋2]:指的是隱匿表達(dá)式實(shí)現(xiàn)的heap.即:以完全二叉樹方式實(shí)現(xiàn)的heap。
            posted @ 2012-11-21 12:07 Jacc.Kim 閱讀(320) | 評論 (0)編輯 收藏

            UPDATE creatureitem I
            SET
              I.xxx =
              (select I.yyy from space s
              where s.type = 1
              AND s.id = i.spaceid
              AND (i.roleid = ''
              OR isnull(i.roleid)))
            posted @ 2012-11-19 17:06 Jacc.Kim 閱讀(106) | 評論 (0)編輯 收藏

                 摘要: 原文轉(zhuǎn)載自:http://www.shnenglu.com/shenhuafeng/archive/2006/12/30/17041.html 模版偏特化--Partial Template Specialization(《Modern C++ Design讀書筆記二》) Partial Template Specialization顧名思義,模版偏特化就是對模版進(jìn)行特化的意思。舉個(gè)例子: na...  閱讀全文
            posted @ 2012-11-15 10:23 Jacc.Kim 閱讀(520) | 評論 (0)編輯 收藏

            原文轉(zhuǎn)載自:http://www.cnblogs.com/cutepig/archive/2009/01/14/1375917.html

            按照默認(rèn)規(guī)定,只有一個(gè)參數(shù)的構(gòu)造函數(shù)也定義了一個(gè)隱式轉(zhuǎn)換,將該構(gòu)造函數(shù)對應(yīng)數(shù)據(jù)類型的數(shù)據(jù)轉(zhuǎn)換為該類對象,如下面所示:
            class String {
            String ( const char* p ); // 用C風(fēng)格的字符串p作為初始化值
            //…
            }
            String s1 = “hello”; //OK 隱式轉(zhuǎn)換,等價(jià)于String s1 = String(“hello”);
             
            但是有的時(shí)候可能會不需要這種隱式轉(zhuǎn)換,如下:
            class String {
                   String ( int n ); //本意是預(yù)先分配n個(gè)字節(jié)給字符串
            String ( const char* p ); // 用C風(fēng)格的字符串p作為初始化值
            //…
            }
             
            下面兩種寫法比較正常:
            String s2 ( 10 );   //OK 分配10個(gè)字節(jié)的空字符串
            String s3 = String ( 10 ); //OK 分配10個(gè)字節(jié)的空字符串
             
            下面兩種寫法就比較疑惑了:
            String s4 = 10; //編譯通過,也是分配10個(gè)字節(jié)的空字符串
            String s5 = ‘a’; //編譯通過,分配int(‘a’)個(gè)字節(jié)的空字符串
             
            s4 和s5 分別把一個(gè)int型和char型,隱式轉(zhuǎn)換成了分配若干字節(jié)的空字符串,容易令人誤解。
            為了避免這種錯(cuò)誤的發(fā)生,我們可以聲明顯示的轉(zhuǎn)換,使用explicit 關(guān)鍵字:
            class String {
                   explicit String ( int n ); //本意是預(yù)先分配n個(gè)字節(jié)給字符串
            String ( const char* p ); // 用C風(fēng)格的字符串p作為初始化值
            //…
            }
            加上explicit就抑制了String ( int n )的隱式轉(zhuǎn)換,
             
            下面兩種寫法仍然正確:
            String s2 ( 10 );   //OK 分配10個(gè)字節(jié)的空字符串
            String s3 = String ( 10 ); //OK 分配10個(gè)字節(jié)的空字符串
             
            下面兩種寫法就不允許了:
            String s4 = 10; //編譯不通過,不允許隱式的轉(zhuǎn)換
            String s5 = ‘a’; //編譯不通過,不允許隱式的轉(zhuǎn)換
             
            因此,某些時(shí)候,explicit 可以有效得防止構(gòu)造函數(shù)的隱式轉(zhuǎn)換帶來的錯(cuò)誤或者誤解

            ----------------------------------------------------------
            explicit   只對構(gòu)造函數(shù)起作用,用來抑制隱式轉(zhuǎn)換。如:  
              class   A   {  
                      A(int   a);  
              };  
              int   Function(A   a);  
               
              當(dāng)調(diào)用   Function(2)   的時(shí)候,2   會隱式轉(zhuǎn)換為   A   類型。這種情況常常不是程序員想要的結(jié)果,所以,要避免之,就可以這樣寫:  
               
              class   A   {  
                      explicit   A(int   a);  
              };  
              int   Function(A   a);  
               
              這樣,當(dāng)調(diào)用   Function(2)   的時(shí)候,編譯器會給出錯(cuò)誤信息(除非   Function   有個(gè)以   int   為參數(shù)的重載形式),這就避免了在程序員毫不知情的情況下出現(xiàn)錯(cuò)誤。

            總結(jié):explicit   只對構(gòu)造函數(shù)起作用,用來抑制隱式轉(zhuǎn)換。

            參考:
            http://blog.csdn.net/smilelance/archive/2007/03/14/1528737.aspx
            http://topic.csdn.net/t/20040509/15/3046021.html
            posted @ 2012-11-13 16:49 Jacc.Kim 閱讀(283) | 評論 (0)編輯 收藏

            原文轉(zhuǎn)載自:http://www.eefocus.com/wang312/blog/2012-05/229203_12ffa.html

            volatile的作用與用法  2011-12-15 13:34

            本文引自百度百科volatile,就當(dāng)作了筆記,和大家一起分享吧。

             

            先說說我的理解,volatile我們叫它“易變的”,是一個(gè)類型修修飾符,一般情況下,我們定義了一個(gè)變量,如果說這個(gè)變量在整個(gè)代碼中都沒有改變,那么編譯器就會把這個(gè)變量放到寄存器中,cpu取值就只在寄存器中取。但是在嵌入式中就會出現(xiàn)特殊情況了,很多時(shí)候,我們在代碼中都不會改變一些變量的值(特別是寄存器的狀態(tài),或者某個(gè)引腳的狀態(tài)),但是硬件很有可能去改變這個(gè)值,如按鍵改變某引腳的狀態(tài)等一些情況,可是編譯器并不知道這個(gè)變量已經(jīng)發(fā)生改變,這個(gè)時(shí)候很有可能編譯器所使用的值和實(shí)際值并不一致,所以C語言中采用volatile來修飾這一類變量,它的作用是讓編譯器每次取值的都會到內(nèi)存單元中去重新讀取該變量的值,而不是直接使用寄存器中的值。

            在代碼中經(jīng)常可以看到(*((volatile unsigned short *)(x)))這樣的代碼,作用也就是這個(gè)了。

            以下是百科原文:

            就象大家更熟悉的const一樣,volatile是一個(gè)類型修飾符(type specifier)。它是被設(shè)計(jì)用來修飾被不同線程訪問和修改的變量。如果沒有volatile,基本上會導(dǎo)致這樣的結(jié)果:要么無法編寫多線程程序,要么編譯器失去大量優(yōu)化的機(jī)會。

             

              推薦一個(gè)定義為volatile的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設(shè)這個(gè)變量的值了。精確地說就是,優(yōu)化器在用到這個(gè)變量時(shí)必須每次都小心地重新讀取這個(gè)變量的值,而不是使用保存在寄存器里的備份。下面是volatile變量的幾個(gè)例子:
              1). 并行設(shè)備的硬件寄存器(如:狀態(tài)寄存器)
              2). 一個(gè)中斷服務(wù)子程序中會訪問到的非自動變量(Non-automatic variables)
              3). 多線程應(yīng)用中被幾個(gè)任務(wù)共享的變量
              回答不出這個(gè)問題的人是不會被雇傭的。我認(rèn)為這是區(qū)分C程序員和嵌入式系統(tǒng)程序員的最基本的問題。嵌入式系統(tǒng)程序員經(jīng)常同硬件、中斷、RTOS等等打交道,所用這些都要求volatile變量。不懂得volatile內(nèi)容將會帶來災(zāi)難。
              假設(shè)被面試者正確地回答了這是問題(嗯,懷疑是否會是這樣),我將稍微深究一下,看一下這家伙是不是真正懂得volatile完全的重要性。
              1). 一個(gè)參數(shù)既可以是const還可以是volatile嗎?解釋為什么。
              2). 一個(gè)指針可以是volatile 嗎?解釋為什么。
              3). 下面的函數(shù)有什么錯(cuò)誤:
              int square(volatile int *ptr)
              {
              return *ptr * *ptr;
              }
              下面是答案:
              1).是的。一個(gè)例子是只讀的狀態(tài)寄存器。它是volatile因?yàn)樗赡鼙灰庀氩坏降馗淖儭K莄onst因?yàn)槌绦虿粦?yīng)該試圖去修改它。
              2). 是的。盡管這并不很常見。一個(gè)例子是當(dāng)一個(gè)中斷服務(wù)子程序修改一個(gè)指向一個(gè)buffer的指針時(shí)。
              3).這段代碼是個(gè)惡作劇。這段代碼的目的是用來返指針*ptr指向值的平方,但是,由于*ptr指向一個(gè)volatile型參數(shù),編譯器將產(chǎn)生類似下面的代碼:
              int square(volatile int *ptr)
              {
              int a,b;
              a = *ptr;
              b = *ptr;
              return a * b;
              }
              由于*ptr的值可能被意想不到地該變,因此a和b可能是不同的。結(jié)果,這段代碼可能返不是你所期望的平方值!正確的代碼如下:
              long square(volatile int *ptr)
              {
              int a;
              a = *ptr;
              return a * a;
              }
              講講我的理解: (歡迎打板子...~~!)
              關(guān)鍵在于兩個(gè)地方:
              1. 編譯器的優(yōu)化 (請高手幫我看看下面的理解)
              在本次線程內(nèi),當(dāng)讀取一個(gè)變量時(shí),為提高存取速度,編譯器優(yōu)化時(shí)有時(shí)會先把變量讀取到一個(gè)寄存器中;以后,再取變量值時(shí),就直接從寄存器中取值;
              當(dāng)變量值在本線程里改變時(shí),會同時(shí)把變量的新值copy到該寄存器中,以便保持一致
              當(dāng)變量在因別的線程等而改變了值,該寄存器的值不會相應(yīng)改變,從而造成應(yīng)用程序讀取的值和實(shí)際的變量值不一致
              當(dāng)該寄存器在因別的線程等而改變了值,原變量的值不會改變,從而造成應(yīng)用程序讀取的值和實(shí)際的變量值不一致
              舉一個(gè)不太準(zhǔn)確的例子:
              發(fā)薪資時(shí),會計(jì)每次都把員工叫來登記他們的銀行卡號;一次會計(jì)為了省事,沒有即時(shí)登記,用了以前登記的銀行卡號;剛好一個(gè)員工的銀行卡丟了,已掛失該銀行卡號;從而造成該員工領(lǐng)不到工資
              員工 -- 原始變量地址
              銀行卡號 -- 原始變量在寄存器的備份
              2. 在什么情況下會出現(xiàn)(如1樓所說)
              1). 并行設(shè)備的硬件寄存器(如:狀態(tài)寄存器)
              2). 一個(gè)中斷服務(wù)子程序中會訪問到的非自動變量(Non-automatic variables)
              3). 多線程應(yīng)用中被幾個(gè)任務(wù)共享的變量
              補(bǔ)充: volatile應(yīng)該解釋為“直接存取原始內(nèi)存地址”比較合適,“易變的”這種解釋簡直有點(diǎn)誤導(dǎo)人;
              “易變”是因?yàn)橥庠谝蛩匾鸬模蠖嗑€程,中斷等,并不是因?yàn)橛胿olatile修飾了的變量就是“易變”了,假如沒有外因,即使用volatile定義,它也不會變化;
              而用volatile定義之后,其實(shí)這個(gè)變量就不會因外因而變化了,可以放心使用了; 大家看看前面那種解釋(易變的)是不是在誤導(dǎo)人
              ------------簡明示例如下:------------------
              volatile關(guān)鍵字是一種類型修飾符,用它聲明的類型變量表示可以被某些編譯器未知的因素更改,比如:操作系統(tǒng)、硬件或者其它線程等。遇到這個(gè)關(guān)鍵字聲明的變量,編譯器對訪問該變量的代碼就不再進(jìn)行優(yōu)化,從而可以提供對特殊地址的穩(wěn)定訪問。
              使用該關(guān)鍵字的例子如下:
              int volatile nVint;
              >>>>當(dāng)要求使用volatile聲明的變量的值的時(shí)候,系統(tǒng)總是重新從它所在的內(nèi)存讀取數(shù)據(jù),即使它前面的指令剛剛從該處讀取過數(shù)據(jù)。而且讀取的數(shù)據(jù)立刻被保存。
              例如:
              volatile int i=10;
              int a = i;
              ...
              //其他代碼,并未明確告訴編譯器,對i進(jìn)行過操作
              int b = i;
              >>>>volatile 指出i是隨時(shí)可能發(fā)生變化的,每次使用它的時(shí)候必須從i的地址中讀取,因而編譯器生成的匯編代碼會重新從i的地址讀取數(shù)據(jù)放在b中。而優(yōu)化做法是,由于編譯器發(fā)現(xiàn)兩次從i讀數(shù)據(jù)的代碼之間的代碼沒有對i進(jìn)行過操作,它會自動把上次讀的數(shù)據(jù)放在b中。而不是重新從i里面讀。這樣以來,如果i是一個(gè)寄存器變量或者表示一個(gè)端口數(shù)據(jù)就容易出錯(cuò),所以說volatile可以保證對特殊地址的穩(wěn)定訪問。
              >>>>注意,在vc6中,一般調(diào)試模式?jīng)]有進(jìn)行代碼優(yōu)化,所以這個(gè)關(guān)鍵字的作用看不出來。下面通過插入?yún)R編代碼,測試有無volatile關(guān)鍵字,對程序最終代碼的影響:
              >>>>首先,用classwizard建一個(gè)win32 console工程,插入一個(gè)voltest.cpp文件,輸入下面的代碼:
              >>
              #i nclude
              void main()
              {
              int i=10;
              int a = i;
              printf("i= %d",a);
              //下面匯編語句的作用就是改變內(nèi)存中i的值,但是又不讓編譯器知道
              __asm {
              mov dword ptr [ebp-4], 20h
              }
              int b = i;
              printf("i= %d",b);
              }
              然后,在調(diào)試版本模式運(yùn)行程序,輸出結(jié)果如下:
              i = 10
              i = 32
              然后,在release版本模式運(yùn)行程序,輸出結(jié)果如下:
              i = 10
              i = 10
              輸出的結(jié)果明顯表明,release模式下,編譯器對代碼進(jìn)行了優(yōu)化,第二次沒有輸出正確的i值。下面,我們把i的聲明加上volatile關(guān)鍵字,看看有什么變化:
              #i nclude
              void main()
              {
              volatile int i=10;
              int a = i;
              printf("i= %d",a);
              __asm {
              mov dword ptr [ebp-4], 20h
              }
              int b = i;
              printf("i= %d",b);
              }
              分別在調(diào)試版本和release版本運(yùn)行程序,輸出都是:
              i = 10
              i = 32
              這說明這個(gè)關(guān)鍵字發(fā)揮了它的作用!
              ------------------------------------
              volatile對應(yīng)的變量可能在你的程序本身不知道的情況下發(fā)生改變
              比如多線程的程序,共同訪問的內(nèi)存當(dāng)中,多個(gè)程序都可以操縱這個(gè)變量
              你自己的程序,是無法判定何時(shí)這個(gè)變量會發(fā)生變化
              還比如,他和一個(gè)外部設(shè)備的某個(gè)狀態(tài)對應(yīng),當(dāng)外部設(shè)備發(fā)生操作的時(shí)候,通過驅(qū)動程序和中斷事件,系統(tǒng)改變了這個(gè)變量的數(shù)值,而你的程序并不知道。
              對于volatile類型的變量,系統(tǒng)每次用到他的時(shí)候都是直接從對應(yīng)的內(nèi)存當(dāng)中提取,而不會利用cache當(dāng)中的原有數(shù)值,以適應(yīng)它的未知何時(shí)會發(fā)生的變化,系統(tǒng)對這種變量的處理不會做優(yōu)化——顯然也是因?yàn)樗臄?shù)值隨時(shí)都可能變化的情況。
              --------------------------------------------------------------------------------
              典型的例子
              for ( int i=0; i<100000; i++);
              這個(gè)語句用來測試空循環(huán)的速度的
              但是編譯器肯定要把它優(yōu)化掉,根本就不執(zhí)行
              如果你寫成
              for ( volatile int i=0; i<100000; i++);
              它就會執(zhí)行了
              volatile的本意是“易變的”
              由于訪問寄存器的速度要快過RAM,所以編譯器一般都會作減少存取外部RAM的優(yōu)化。比如:
              static int i=0;
              int main(void)
              {
              ...
              while (1)
              {
              if (i) dosomething();
              }
              }
              /* Interrupt service routine. */
              void ISR_2(void)
              {
              i=1;
              }
              程序的本意是希望ISR_2中斷產(chǎn)生時(shí),在main當(dāng)中調(diào)用dosomething函數(shù),但是,由于編譯器判斷在main函數(shù)里面沒有修改過i,因此
              可能只執(zhí)行一次對從i到某寄存器的讀操作,然后每次if判斷都只使用這個(gè)寄存器里面的“i副本”,導(dǎo)致dosomething永遠(yuǎn)也不會被
              調(diào)用。如果將將變量加上volatile修飾,則編譯器保證對此變量的讀寫操作都不會被優(yōu)化(肯定執(zhí)行)。此例中i也應(yīng)該如此說明。
              一般說來,volatile用在如下的幾個(gè)地方:
              1、中斷服務(wù)程序中修改的供其它程序檢測的變量需要加volatile;
              2、多任務(wù)環(huán)境下各任務(wù)間共享的標(biāo)志應(yīng)該加volatile;
              3、存儲器映射的硬件寄存器通常也要加volatile說明,因?yàn)槊看螌λ淖x寫都可能由不同意義;
              另外,以上這幾種情況經(jīng)常還要同時(shí)考慮數(shù)據(jù)的完整性(相互關(guān)聯(lián)的幾個(gè)標(biāo)志讀了一半被打斷了重寫),在1中可以通過關(guān)中斷來實(shí)
              現(xiàn),2中可以禁止任務(wù)調(diào)度,3中則只能依靠硬件的良好設(shè)計(jì)了。
            posted @ 2012-11-11 22:40 Jacc.Kim 閱讀(250) | 評論 (0)編輯 收藏

            由于在處理游戲服務(wù)端時(shí),必須考慮到使用的處理。在此,使用了boost中的時(shí)間相關(guān)的內(nèi)容。
            用boost的好處很多,下面是項(xiàng)目中對此的一點(diǎn)應(yīng)用小結(jié):
            1) 支持跨平臺。
            2) 時(shí)間的精確度極高。取得毫秒級的絕對沒問題。(似乎微秒級的也可以)
            3) 用法方便。

            using namespace boost::posix_time;
            using namespace boost::gregorian;
            //using boost::gregorian::date;

            #include <boost/date_time/posix_time/posix_time.hpp>
            #define BOOST_DATE_TIME_SOURCE


            static ptime const epoch(date(1970, 1, 1));//一個(gè)基準(zhǔn)點(diǎn)。
            std::string currtimestamp = CommonHelper::format("%I64u", (WE::uint64)((microsec_clock::universal_time() - epoch).total_milliseconds()));
            //提示:
               1) microsec_clock::universal_time()是取得格林威治時(shí)間。
               2) 如果是:microsec_clock::local_time()則取得的是本地時(shí)間。
               3) 如果想取得北京時(shí)間,則只需要加上8小時(shí)即可。microsec_clock::universal_time() + hours(8);
               4) 上面的語句是計(jì)算當(dāng)前格林威治時(shí)間的時(shí)間戳。

            4) boost::posix_time::ptime 因重載了許多操作符運(yùn)算。因此,對它的使用就如同基本類型一樣。如:可以很方便計(jì)算兩點(diǎn)時(shí)間點(diǎn)的差距。

            boost::posix_time::ptime pt1(date(xxxx, x, x), time_duration(10, 1, 23));
            //上面也可以這樣寫:boost::posix_time::ptime pt1(date(xxxx, x, x), time_duration(hours(10), minutes(1), seconds(23)));
            //再比如:boost::posix_time::ptime pt1(date(xxxx, x, x), hours(10));如果想要詳細(xì)了解,請自行研究boost源碼。

            boost::posix_time::ptime pt2(.....);//這邊的構(gòu)造函數(shù)參數(shù)就不寫了。請自行參考上面的語句。

            time_duration td = pt1 - pt2;//注意:ptime是不支持 + 的。因?yàn)樗鼪]有重載該操作。計(jì)算它們的加,是沒有意義的。而 - 有意義。所以可如此操作。

            5) 取得日期,取得時(shí)間都很方便。


            此次,就暫時(shí)就寫這么多吧。
            posted @ 2012-11-06 20:18 Jacc.Kim 閱讀(5841) | 評論 (0)編輯 收藏

            原文轉(zhuǎn)處:http://www.shnenglu.com/software8/archive/2012/10/09/193049.html

            一、面向?qū)ο笫荂++的重要特性.
               但是c++在c的基礎(chǔ)上新增加的幾點(diǎn)優(yōu)化也是很耀眼的,就const直接可以取代c中的#define,以下幾點(diǎn)很重要,學(xué)不好后果也也很嚴(yán)重
            1. 限定符聲明變量只能被讀
            [cpp] view plaincopyprint?
            const int i=5;  
              int j=0;  
              ...  
              i=j; //非法,導(dǎo)致編譯錯(cuò)誤  
              j=i; //合法  
            2. 必須初始化
            [cpp] view plaincopyprint?
            const int i=5; //合法  
              const int j; //非法,導(dǎo)致編譯錯(cuò)誤  
            3. 在另一連接文件中引用const常量
            [cpp] view plaincopyprint?
            extern const int i; //合法  
            extern const int j=10; //非法,常量不可以被再次賦值  
                  在C++中const默認(rèn)具有內(nèi)部鏈接性,也就是說如果聲明const int i = 10;等價(jià)于 static const int i =10;通常可以將const 常量和inline函數(shù)放在頭文件中。所以要在A文件定義時(shí)用extern const int i=10;B文件中引用時(shí)用extern const int i。在C中恰好相反,const 默認(rèn)具有外部鏈接屬性,所以在引用外部const 常量時(shí)無需加extern。
            4. 便于進(jìn)行類型檢查
              用const方法可以使編譯器對處理內(nèi)容有更多了解。 
            [cpp] view plaincopyprint?
            #define I=10  
            const long &i=10; /*dapingguo提醒:由于編譯器的優(yōu)化,使得在const long i=10; 時(shí)i不被分配內(nèi)存,而是已10直接代入以后的引用中,以致在以后的代碼中沒有錯(cuò)誤,為達(dá)到說教效 
              果,特別地用&i明確地給出了i的內(nèi)存分配。不過一旦你關(guān)閉所 
              有優(yōu)化措施,即使const long i=10;也會引起后面的編譯錯(cuò)誤。*/  
              char h=I; //沒有錯(cuò)  
              char h=i; //編譯警告,可能由于數(shù)的截短帶來錯(cuò)誤賦值。  
            5. 可以避免不必要的內(nèi)存分配
            [cpp] view plaincopyprint?
            #define STRING "abcdefghijklmn\n"  
              const char string[]="abcdefghijklm\n";  
              ...  
              printf(STRING); //為STRING分配了第一次內(nèi)存  
              printf(string); //為string一次分配了內(nèi)存,以后不再分配  
              ...  
              printf(STRING); //為STRING分配了第二次內(nèi)存  
              printf(string);  
              ...    
              由于const定義常量從匯編的角度來看,只是給出了對應(yīng)的內(nèi)存地址, 而不是象#define一樣給出的是立即數(shù),所以,const定義的常量在程序運(yùn)行過程中只有一份拷貝,而#define定義的常量在內(nèi)存中有若干個(gè)拷貝。但是這個(gè)地方也有點(diǎn)其他問題,大家自己好好研究下吧,給個(gè)例子:
            [cpp] view plaincopyprint?
            #include <stdio.h>   
            #define ABCD    "ABCD"  
            const char a[] = "ABCD";  
            static void  
            p(const char *s)  
            {  
                    printf("%X\n", s);  
            }  
            int   main(void)  
            {  
                    const char b[] = "ABCD";  
              
                    p(ABCD);  
                    p(ABCD);  
                    p(a);  
                    p(b);  
                    return 0;  
            }  
            [plain] view plaincopyprint?
            程序輸出為:  
            400748  
            400748  
            40073F  
            FFFFEB00  
            編譯器管不了你運(yùn)行是更改所謂的const int 變量。 但對于你聲明的const int 變量。在它的編譯空間里,它保留了這個(gè)數(shù)值。 所以,調(diào)用的時(shí)候,把立即數(shù)傳過去了(這個(gè)值在編譯時(shí)就確定了)。
            6. 可以通過函數(shù)對常量進(jìn)行初始化
            [cpp] view plaincopyprint?
            int value();    
            const int i=value();  
              dapingguo說:假定對ROM編寫程序時(shí),由于目標(biāo)代碼的不可改寫,本語句將會無效,不過可以變通一下:
              const int &i=value();
              只要令i的地址處于ROM之外,即可實(shí)現(xiàn):i通過函數(shù)初始化,而其值有不會被修改。
            7. 是不是const的常量值一定不可以被修改呢?
              觀察以下一段代碼:  
            [cpp] view plaincopyprint?
            const int i=0;  
            int *p=(int*)&i;  
            p=100;  
                 通過強(qiáng)制類型轉(zhuǎn)換,將地址賦給變量,再作修改即可以改變const常量值。
                 說明了申明為常量的數(shù)據(jù)也可能被改變。我這里補(bǔ)充的是不要對const 的濫用。強(qiáng)制繞過const 檢查可能引起運(yùn)行錯(cuò)誤。把const int i=0 聲明在函數(shù)內(nèi),能夠達(dá)到你的目的把const int i=0 聲明為全局變量,雖然仍然能夠用強(qiáng)制轉(zhuǎn)換繞過編譯器檢查,但會引起運(yùn)行錯(cuò)誤。
            可參考下例: 
            [cpp] view plaincopyprint?
            const int j=50;  
            void main()  
            {  
                const int i=0;  
                int *p=(int*)&i;  
                *p=100;   
                int *p2=(int *)&j;  
                *p2=200;  // runtime error  
                cout << &i << &j;  
                system("pause");  
            }  
            8. 請分清數(shù)值常量和指針常量,以下聲明頗為玩味:
            [cpp] view plaincopyprint?
            int ii=0;  
            const int i=0; //i是常量,i的值不會被修改  
            const int *p1i=&i; //指針p1i所指內(nèi)容是常量,可以不初始化  
            int * const p2i=&ii //指針p2i是常量,所指內(nèi)容可修改  
            const int * const p3i=&i; //指針p3i是常量,所指內(nèi)容也是常量  
            p1i=&ii //不合法 左操作數(shù)包含“int *”類型  
            *p2i=100; //不合法  右操作數(shù)包含“int *const ”類型  
            指向常量的指針并不能保證所指向的值不被改變
            [cpp] view plaincopyprint?
            const int i=10;  
            void main()  
            {  
                const int j=20;  
                int k = 30;  
                const int * p1=&i;  
                const int * p2 = &j;  
                const int * p3 = &k;  
                // i=80; fail  
                // j= 20; fail  
                // *p3 = 50; fail  
                // 以上三種均未逃過編譯器檢查  
                k=80;   // succeed 逃過了編譯器檢查。 *p3 不行,但直接改k 允許。  
                system("pause");  
            }  
            所以對const 的理解,全局變量不僅有編譯的保護(hù),還有運(yùn)行的保護(hù)。對局部變量,則只有編譯的保護(hù)。
            所以,當(dāng)你聲明一個(gè)局部const變量時(shí),它可能在運(yùn)行期被改變。
            二、關(guān)于C++中的const關(guān)鍵字的用法非常靈活
            1. const常量,如:
            [cpp] view plaincopyprint?
            const int max = 100;  <span style="font-family: simsun; "> </span>  
            優(yōu)點(diǎn):const常量有數(shù)據(jù)類型,而宏常量沒有數(shù)據(jù)類型。編譯器可以對前者進(jìn)行類型安全檢查,而對后者只進(jìn)行字符替換,沒有類型安全檢查,并且在字符替換時(shí)可能會產(chǎn)生意料不到的錯(cuò)誤(邊際效應(yīng))
            2. const 修飾類的數(shù)據(jù)成員。
            如:
            [cpp] view plaincopyprint?
            class A  
            {  
              const int size;  
              …    
            }  
            const數(shù)據(jù)成員只在某個(gè)對象生存期內(nèi)是常量,而對于整個(gè)類而言卻是可變的。因?yàn)轭惪梢詣?chuàng)建多個(gè)對象,不同的對象其const數(shù)據(jù)成員的值可以不同。所以不能在類聲明中初始化const數(shù)據(jù)成員,因?yàn)轭惖膶ο笪幢粍?chuàng)建時(shí),編譯器不知道const 數(shù)據(jù)成員的值是什么。如
            [cpp] view plaincopyprint?
            class A  
            {  
                const int size = 100; //錯(cuò)誤  
                int array[size]; //錯(cuò)誤,未知的size  
            }  
            const數(shù)據(jù)成員的初始化只能在類的構(gòu)造函數(shù)的初始化表中進(jìn)行。要想建立在整個(gè)類中都恒定的常量,應(yīng)該用類中的枚舉常量來實(shí)現(xiàn)。如
            [cpp] view plaincopyprint?
            class A  
            {  
                 …  
                 enum {size1=100, size2 = 200 };  
                 int array1[size1];  
                 int array2[size2];    
            }  
            枚舉常量不會占用對象的存儲空間,他們在編譯時(shí)被全部求值。但是枚舉常量的隱含數(shù)據(jù)類型是整數(shù),其最大值有限,且不能表示浮點(diǎn)數(shù)。
            3. const修飾指針的情況,見下式:
            [cpp] view plaincopyprint?
            int b = 500;    
            const int* a = &b;//[1]  
            int const *a = &b;//[2]  
            int* const a = &b;//[3]   
            const int* const a = &b;//[4]   
            如果你能區(qū)分出上述四種情況,那么,恭喜你,你已經(jīng)邁出了可喜的一步。不知道,也沒關(guān)系,我們可以參考《Effective c++》Item21上的做法,如果const位于星號的左側(cè),則const就是用來修飾指針?biāo)赶虻淖兞浚粗羔樦赶驗(yàn)槌A浚蝗绻鹀onst位于星號的右側(cè),const就是修飾指針本身,即指針本身是常量。因此,[1]和[2]的情況相同,都是指針?biāo)赶虻膬?nèi)容為常量(const放在變量聲明符的位置無關(guān)),這種情況下不允許對內(nèi)容進(jìn)行更改操作,如不能*a = 3 ;[3]為指針本身是常量,而指針?biāo)赶虻膬?nèi)容不是常量,這種情況下不能對指針本身進(jìn)行更改操作,如a++是錯(cuò)誤的;[4]為指針本身和指向的內(nèi)容均為常量。  
            4. const的初始化  
            先看一下const變量初始化的情況  
            1) 非指針const常量初始化的情況:A b;  
            [cpp] view plaincopyprint?
            const A a = b;    
            2) 指針const常量初始化的情況:
            [cpp] view plaincopyprint?
            A* d = new A();    
            const A* c = d;  //或者:const A* c = new A();    
            3)引用const常量初始化的情況:  
            [cpp] view plaincopyprint?
            A f;    
            const A& e = f; // 這樣作e只能訪問聲明為const的函數(shù),而不能訪問一般的成員函數(shù)<span style="font-family: simsun; font-size: 14px; line-height: 23px; text-align: left; ">;  </span>  
              [思考1]: 以下的這種賦值方法正確嗎?  
              const A* c=new A();  
              A* e = c;  
              [思考2]: 以下的這種賦值方法正確嗎?  
              A* const c = new A();  
              A* b = c;
            5. 函數(shù)聲明中的運(yùn)用
                  另外const 的一些強(qiáng)大的功能在于它在函數(shù)聲明中的應(yīng)用。在一個(gè)函數(shù)聲明中,const 可以修飾函數(shù)的返回值,或某個(gè)參數(shù);對于成員函數(shù),還可以修飾是整個(gè)函數(shù)。有如下幾種情況,以下會逐漸的說明用法:A& operator=(const A& a);  
            [cpp] view plaincopyprint?
            void fun0(const A* a );    
            void fun1( ) const; // fun1( ) 為類成員函數(shù)   
            const A fun2( );  
            1) 修飾參數(shù)的const,如:
            [cpp] view plaincopyprint?
            void fun0(const A* a );  
            void fun1(const A& a);    
                 調(diào)用函數(shù)的時(shí)候,用相應(yīng)的變量初始化const常量,則在函數(shù)體中,按照const所修飾的部分進(jìn)行常量化,如形參為const A* a,則不能對傳遞進(jìn)來的指針的內(nèi)容進(jìn)行改變,保護(hù)了原指針?biāo)赶虻膬?nèi)容;如形參為const A& a,則不能對傳遞進(jìn)來的引用對象進(jìn)行改變,保護(hù)了原對象的屬性。  
            [注意]:參數(shù)const通常用于參數(shù)為指針或引用的情況,且只能修飾輸入?yún)?shù);若輸入?yún)?shù)采用“值傳遞”方式,由于函數(shù)將自動產(chǎn)生臨時(shí)變量用于復(fù)制該參數(shù),該參數(shù)本就不需要保護(hù),所以不用const修飾。
            [總結(jié)]     
                   對于非內(nèi)部數(shù)據(jù)類型的輸入?yún)?shù),因該將“值傳遞”的方式改為“const引用傳遞”,目的是為了提高效率。例如,將void Func(A a)改為void Func(const A &a)。對于內(nèi)部數(shù)據(jù)類型的輸入?yún)?shù),不要將“值傳遞”的方式改為“const引用傳遞”。否則既達(dá)不到提高效率的目的,又降低了函數(shù)的可理解性。例如void Func(int x)不應(yīng)該改為void Func(const int &x); 修飾返回值的const,如:
            [cpp] view plaincopyprint?
            const A fun2( );  
            const A* fun3( );<span style="font-family: simsun; ">  </span>  
            這樣聲明了返回值后,const按照"修飾原則"進(jìn)行修飾,起到相應(yīng)的保護(hù)作用。
            [cpp] view plaincopyprint?
            const Rational operator*(const Rational& lhs, const Rational& rhs)    
            {    
                  return Rational(lhs.numerator() * rhs.numerator(),    
                  lhs.denominator() * rhs.denominator());    
            } <span style="font-family: simsun; "> </span>  
            返回值用const修飾可以防止允許這樣的操作發(fā)生:
            [cpp] view plaincopyprint?
            Rational a,b;    
            Radional c;    
            (a*b) = c; <span style="font-family: simsun; "> </span>  
            一般用const修飾返回值為對象本身(非引用和指針)的情況多用于二目操作符重載函數(shù)并產(chǎn)生新對象的時(shí)候。  
                   一般情況下,函數(shù)的返回值為某個(gè)對象時(shí),如果將其聲明為const時(shí),多用于操作符的重載。通常,不建議用const修飾函數(shù)的返回值類型為某個(gè)對象或?qū)δ硞€(gè)對象引用的情況。原因如下:如果返回值為某個(gè)對象為const(const A test = A 實(shí)例)或某個(gè)對象的引用為const(const A& test = A實(shí)例) ,則返回值具有const屬性,則返回實(shí)例只能訪問類A中的公有(保護(hù))數(shù)據(jù)成員和const成員函數(shù),并且不允許對其進(jìn)行賦值操作,這在一般情況下很少用到。如果給采用“指針傳遞”方式的函數(shù)返回值加const修飾,那么函數(shù)返回值(即指針)的內(nèi)容不能被修改,該返回值只能被賦給加const 修飾的同類型指針。如:
            [cpp] view plaincopyprint?
            const char * GetString(void);  
            如下語句將出現(xiàn)編譯錯(cuò)誤:
            [cpp] view plaincopyprint?
            char *str=GetString();  
            正確的用法是:
            [cpp] view plaincopyprint?
            const char *str=GetString();  
                 函數(shù)返回值采用“引用傳遞”的場合不多,這種方式一般只出現(xiàn)在類的賻值函數(shù)中,目的是為了實(shí)現(xiàn)鏈?zhǔn)奖磉_(dá)。如:
            [cpp] view plaincopyprint?
            class A  
            {  
                …  
                A &operate = (const A &other); //負(fù)值函數(shù)  
            }  
               A a,b,c; //a,b,c為A的對象  
               …  
               a=b=c; //正常  
               (a=b)=c; //不正常,但是合法  
            若負(fù)值函數(shù)的返回值加const修飾,那么該返回值的內(nèi)容不允許修改,上例中a=b=c依然正確。(a=b)=c就不正確了。
            [思考3]: 這樣定義賦值操作符重載函數(shù)可以嗎?  
            const A& operator=(const A& a);
                類成員函數(shù)中const的使用,一般放在函數(shù)體后,形如:void fun() const;  任何不會修改數(shù)據(jù)成員的函數(shù)都因該聲明為const類型。如果在編寫const成員函數(shù)時(shí),不慎修改了數(shù)據(jù)成員,或者調(diào)用了其他非const成員函數(shù),編譯器將報(bào)錯(cuò),這大大提高了程序的健壯性。如:
            [cpp] view plaincopyprint?
            class Stack  
            {  
            public:  
              void Push(int elem);  
              int Pop(void);  
              int GetCount(void) const; //const 成員函數(shù)  
            private:    
              int m_num;  
              int m_data[100];  
            };  
            int Stack::GetCount(void) const  
            {  
              ++m_num; //編譯錯(cuò)誤,企圖修改數(shù)據(jù)成員m_num  
              Pop(); //編譯錯(cuò)誤,企圖調(diào)用非const函數(shù)  
              Return m_num;  
            }  
            [思考題答案]  
            1 這種方法不正確,因?yàn)槁暶髦羔樀哪康氖菫榱藢ζ渲赶虻膬?nèi)容進(jìn)行改變,而聲明的指針e指向的是一個(gè)常量,所以不正確;  
            2 這種方法正確,因?yàn)槁暶髦羔標(biāo)赶虻膬?nèi)容可變;  
            3 這種做法不正確;  
            在const A::operator=(const A& a)中,參數(shù)列表中的const的用法正確,而當(dāng)這樣連續(xù)賦值的時(shí)侯,問題就出現(xiàn)了:  
            [cpp] view plaincopyprint?
            A a,b,c:    
            (a=b)=c; <span style="font-family: simsun; "> </span>  
            因?yàn)閍.operator=(b)的返回值是對a的const引用,不能再將c賦值給const常量。
            posted @ 2012-10-09 10:40 Jacc.Kim 閱讀(237) | 評論 (0)編輯 收藏

            原文出處:http://zhidao.baidu.com/question/385301217.html

            [轉(zhuǎn)載] #include<iomanip>怎么用?在c++中

            在c++程序里面經(jīng)常見到下面的頭文件
              #include <iomanip>
              io代表輸入輸出,manip是manipulator(操縱器)的縮寫(在c++上只能通過輸入縮寫才有效。)
              iomanip的作用:
              主要是對cin,cout之類的一些操縱運(yùn)算子,比如setfill,setw,setbase,setprecision等等。它是I/O流控制頭文件,就像C里面的格式化輸出一樣.以下是一些常見的控制函數(shù)的:
              dec 置基數(shù)為10 相當(dāng)于"%d"
              hex 置基數(shù)為16 相當(dāng)于"%X"
              oct 置基數(shù)為8 相當(dāng)于"%o"
              setfill( 'c' ) 設(shè)填充字符為c
              setprecision( n ) 設(shè)顯示小數(shù)精度為n位
              setw( n ) 設(shè)域?qū)挒閚個(gè)字符
              這個(gè)控制符的意思是保證輸出寬度為n。如:
              cout << setw( 3 ) << 1 << setw( 3 ) << 10 << setw( 3 ) << 100 << endl; 輸出結(jié)果為
              1 10100 (默認(rèn)是右對齊)當(dāng)輸出長度大于3時(shí)(<<1000),setw(3)不起作用。
              ▲setw(n)用法: 通俗地講就是預(yù)設(shè)寬度
              如 cout<<setw(5)<<255<<endl;
              結(jié)果是:
              (空格)(空格)255
              ▲setfill(char c) 用法 : 就是在預(yù)設(shè)寬度中如果已存在沒用完的寬度大小,則用設(shè)置的字符c填充
              如 cout<<setfill(‘@‘)<<setw(5)<<255<<endl;
              結(jié)果是:
              @@255
              ▲setbase(int n) : 將數(shù)字轉(zhuǎn)換為 n 進(jìn)制.
              如 cout<<setbase(8)<<setw(5)<<255<<endl;
              cout<<setbase(10)<<setw(5)<<255<<endl;
              cout<<setbase(16)<<255<<endl;
              結(jié)果是:
              (空格)(空格)377
              (空格)(空格) 255
              (空格)(空格)(空格) f f
              ▲ setprecision用法
              使用setprecision(n)可控制輸出流顯示浮點(diǎn)數(shù)的數(shù)字個(gè)數(shù)。C++默認(rèn)的流輸出數(shù)值有效位是6。
              如果setprecision(n)與setiosflags(ios::fixed)合用,可以控制小數(shù)點(diǎn)右邊的數(shù)字個(gè)數(shù)。setiosflags(ios::fixed)是用定點(diǎn)方式表示實(shí)數(shù)。
              如果與setiosflags(ios::scientific)合用, 可以控制指數(shù)表示法的小數(shù)位數(shù)。setiosflags(ios::scientific)是用指數(shù)方式表示實(shí)數(shù)。
              setiosflags(ios::fixed) 固定的浮點(diǎn)顯示
              setiosflags(ios::scientific) 指數(shù)表示
              setiosflags(ios::left) 左對齊
              setiosflags(ios::right) 右對齊
              setiosflags(ios::skipws) 忽略前導(dǎo)空白
              setiosflags(ios::uppercase) 16進(jìn)制數(shù)大寫輸出
              setiosflags(ios::lowercase) 16進(jìn)制小寫輸出
              setiosflags(ios::showpoint) 強(qiáng)制顯示小數(shù)點(diǎn)
              setiosflags(ios::showpos) 強(qiáng)制顯示符號
              舉例:
              #include <iostream.h>
              #include <iomanip.h>
              using namespace std;
              int main()
              {
              cout<<12345.0<<endl;//輸出"12345"
              cout<<setiosflags(ios::fixed)<<setprecision(3)<<1.2345<<endl;輸出"1.235"(應(yīng)該輸出"1.235",而不是"1.234".因?yàn)橐裱?舍5入的原則)
              cout<<setiosflags(ios::scientific)<<12345.0<<endl;//輸出"1.234500e+004 "
              cout<<setprecision(3)<<12345.0<<endl;//輸出"1.23e+004 "
              return 0;
              }
            posted @ 2012-09-27 17:14 Jacc.Kim 閱讀(404) | 評論 (0)編輯 收藏

            原來出處:http://blog.csdn.net/beyondhaven/article/details/4204345

            [轉(zhuǎn)載] C++模板:函數(shù)模板和模板函數(shù)

            1.函數(shù)模板的聲明和模板函數(shù)的生成

             

            1.1函數(shù)模板的聲明

            函數(shù)模板可以用來創(chuàng)建一個(gè)通用的函數(shù),以支持多種不同的形參,避免重載函數(shù)的函數(shù)體重復(fù)設(shè)計(jì)。它的最大特點(diǎn)是把函數(shù)使用的數(shù)據(jù)類型作為參數(shù)。

            函數(shù)模板的聲明形式為:

            template<typename 數(shù)據(jù)類型參數(shù)標(biāo)識符>

            <返回類型><函數(shù)名>(參數(shù)表)

            {

                函數(shù)體

            }

            其中,template是定義模板函數(shù)的關(guān)鍵字;template后面的尖括號不能省略;typename(或class)是聲明數(shù)據(jù)類型參數(shù)標(biāo)識符的關(guān)鍵字,用以說明它后面的標(biāo)識符是數(shù)據(jù)類型標(biāo)識符。這樣,在以后定義的這個(gè)函數(shù)中,凡希望根據(jù)實(shí)參數(shù)據(jù)類型來確定數(shù)據(jù)類型的變量,都可以用數(shù)據(jù)類型參數(shù)標(biāo)識符來說明,從而使這個(gè)變量可以適應(yīng)不同的數(shù)據(jù)類型。例如:

            template<typename T>

            T fuc(T x, int y)

            {

                T x;

                //……

            }

            如果主調(diào)函數(shù)中有以下語句:

            double d;

            int a;

            fuc(d,a);

            則系統(tǒng)將用實(shí)參d的數(shù)據(jù)類型double去代替函數(shù)模板中的T生成函數(shù):

            double fuc(double x,int y)

            {

                double x;

                //……

            }

            函數(shù)模板只是聲明了一個(gè)函數(shù)的描述即模板,不是一個(gè)可以直接執(zhí)行的函數(shù),只有根據(jù)實(shí)際情況用實(shí)參的數(shù)據(jù)類型代替類型參數(shù)標(biāo)識符之后,才能產(chǎn)生真正的函數(shù)。

            關(guān)鍵字typename也可以使用關(guān)鍵字class,這時(shí)數(shù)據(jù)類型參數(shù)標(biāo)識符就可以使用所有的C++數(shù)據(jù)類型。

            1.2.模板函數(shù)的生成

            函數(shù)模板的數(shù)據(jù)類型參數(shù)標(biāo)識符實(shí)際上是一個(gè)類型形參,在使用函數(shù)模板時(shí),要將這個(gè)形參實(shí)例化為確定的數(shù)據(jù)類型。將類型形參實(shí)例化的參數(shù)稱為模板實(shí)參,用模板實(shí)參實(shí)例化的函數(shù)稱為模板函數(shù)。模板函數(shù)的生成就是將函數(shù)模板的類型形參實(shí)例化的過程。例如:

            使用中應(yīng)注意的幾個(gè)問題:

            ⑴ 函數(shù)模板允許使用多個(gè)類型參數(shù),但在template定義部分的每個(gè)形參前必須有關(guān)鍵字typename或class,即:

            template<class 數(shù)據(jù)類型參數(shù)標(biāo)識符1,…,class 數(shù)據(jù)類型參數(shù)標(biāo)識符n>

            <返回類型><函數(shù)名>(參數(shù)表)

            {

                 函數(shù)體

            }

            ⑵ 在template語句與函數(shù)模板定義語句<返回類型>之間不允許有別的語句。如下面的聲明是錯(cuò)誤的:

            template<class T>

            int I;

            T min(T x,T y)

            {

               函數(shù)體

            }

            ⑶ 模板函數(shù)類似于重載函數(shù),但兩者有很大區(qū)別:函數(shù)重載時(shí),每個(gè)函數(shù)體內(nèi)可以執(zhí)行不同的動作,但同一個(gè)函數(shù)模板實(shí)例化后的模板函數(shù)都必須執(zhí)行相同的動作。


            2 函數(shù)模板的異常處理

            函數(shù)模板中的模板形參可實(shí)例化為各種類型,但當(dāng)實(shí)例化模板形參的各模板實(shí)參之間不完全一致時(shí),就可能發(fā)生錯(cuò)誤,如:

            template<typename T>       

            void min(T &x, T &y)

            {  return (x<y)?x:y;  }

            void func(int i, char j)

            {

               min(i, i);

               min(j, j);

               min(i, j);

               min(j, i);

            }

            例子中的后兩個(gè)調(diào)用是錯(cuò)誤的,出現(xiàn)錯(cuò)誤的原因是,在調(diào)用時(shí),編譯器按最先遇到的實(shí)參的類型隱含地生成一個(gè)模板函數(shù),并用它對所有模板函數(shù)進(jìn)行一致性檢查,例如對語句

            min(i, j);

            先遇到的實(shí)參i是整型的,編譯器就將模板形參解釋為整型,此后出現(xiàn)的模板實(shí)參j不能解釋為整型而產(chǎn)生錯(cuò)誤,此時(shí)沒有隱含的類型轉(zhuǎn)換功能。解決此種異常的方法有兩種:

            ⑴采用強(qiáng)制類型轉(zhuǎn)換,如將語句min(i, j);改寫為min(i,int( j));

            ⑵用非模板函數(shù)重載函數(shù)模板

            方法有兩種:

            ① 借用函數(shù)模板的函數(shù)體

            此時(shí)只聲明非模板函數(shù)的原型,它的函數(shù)體借用函數(shù)模板的函數(shù)體。如改寫上面的例子如下:

            template<typename T>       

            void min(T &x, T &y)

            {  return (x<y)?x:y;  }

            int min(int,int);

            void func(int i, char j)

            {

               min(i, i);

               min(j, j);

               min(i, j);

               min(j, i);

            }

            執(zhí)行該程序就不會出錯(cuò)了,因?yàn)橹剌d函數(shù)支持?jǐn)?shù)據(jù)間的隱式類型轉(zhuǎn)換。

            ② 重新定義函數(shù)體

            就像一般的重載函數(shù)一樣,重新定義一個(gè)完整的非模板函數(shù),它所帶的參數(shù)可以隨意。C++中,函數(shù)模板與同名的非模板函數(shù)重載時(shí),應(yīng)遵循下列調(diào)用原則:

            • 尋找一個(gè)參數(shù)完全匹配的函數(shù),若找到就調(diào)用它。若參數(shù)完全匹配的函數(shù)多于一個(gè),則這個(gè)調(diào)用是一個(gè)錯(cuò)誤的調(diào)用。

            • 尋找一個(gè)函數(shù)模板,若找到就將其實(shí)例化生成一個(gè)匹配的模板函數(shù)并調(diào)用它。

            • 若上面兩條都失敗,則使用函數(shù)重載的方法,通過類型轉(zhuǎn)換產(chǎn)生參數(shù)匹配,若找到就調(diào)用它。

            •若上面三條都失敗,還沒有找都匹配的函數(shù),則這個(gè)調(diào)用是一個(gè)錯(cuò)誤的調(diào)用。


            此為轉(zhuǎn)載文章,文章出處沒有了。請大家見諒。


            posted @ 2012-09-27 16:59 Jacc.Kim 閱讀(207) | 評論 (0)編輯 收藏

            僅列出標(biāo)題
            共14頁: First 3 4 5 6 7 8 9 10 11 Last 
            久久久91精品国产一区二区三区| 久久国产精品99精品国产987| 青青草原综合久久| 欧美精品久久久久久久自慰| 久久无码AV中文出轨人妻| 久久久久国产| 久久久久国产一级毛片高清板 | 99热精品久久只有精品| 国内精品久久久人妻中文字幕| 亚洲AV无一区二区三区久久| 伊人久久大香线蕉亚洲五月天 | 狠狠色丁香婷婷久久综合| 久久露脸国产精品| 午夜精品久久久久久久无码| 国产精品久久新婚兰兰| 久久精品一区二区三区AV| 亚洲午夜久久久影院| 人妻少妇久久中文字幕| 久久久久久国产精品无码超碰| avtt天堂网久久精品| 久久免费精品视频| 久久精品国产只有精品66| 一本色道久久88综合日韩精品 | 少妇人妻88久久中文字幕| 69久久夜色精品国产69| 国产精品美女久久久免费| 香蕉99久久国产综合精品宅男自| 一本久久综合亚洲鲁鲁五月天亚洲欧美一区二区 | 久久99九九国产免费看小说| 伊人久久大香线蕉av不卡| 国产情侣久久久久aⅴ免费| 99热热久久这里只有精品68| 中文字幕精品久久| 国产V亚洲V天堂无码久久久| 久久AⅤ人妻少妇嫩草影院| 囯产极品美女高潮无套久久久| 激情伊人五月天久久综合| 久久国产福利免费| 久久精品国产亚洲精品2020| 精品久久人人爽天天玩人人妻| 狠狠综合久久综合88亚洲|