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

            elva

            解析“extern”


            link: http://blog.csdn.net/keensword/archive/2005/06/23/401114.aspx

            解析“extern

             

             

            1、 聲明外部變量

             

             

            現(xiàn)代編譯器一般采用按文件編譯的方式,因此在編譯時(shí),各個(gè)文件中定義的全局變量是

            互相透明的,也就是說,在編譯時(shí),全局變量的可見域限制在文件內(nèi)部。下面舉一個(gè)簡單的例子。創(chuàng)建一個(gè)工程,里面含有A.cppB.cpp兩個(gè)簡單的C++源文件:

            //A.cpp

             

             

            int i;

             

             

             

             

            void main()

             

             

            {

             

             

            }

             

             

             

             

             

             

             

             

             

             

             

             

            //B.cpp

             

             

            int i;

             

             

             

             

             

             

                  

            這兩個(gè)文件極為簡單,在A.cpp中我們定義了一個(gè)全局變量i,在B中我們也定義了一個(gè)全局變量i

            我們對AB分別編譯,都可以正常通過編譯,但是進(jìn)行鏈接的時(shí)候,卻出現(xiàn)了錯(cuò)誤,錯(cuò)誤提示如下:

            Linking...

             

             

            B.obj : error LNK2005: "int i" (?i@@3HA) already defined in A.obj

             

             

            Debug/A.exe : fatal error LNK1169: one or more multiply defined symbols found

             

             

            Error executing link.exe.

             

             

             

             

            A.exe - 2 error(s), 0 warning(s)

             

             

             

             

             

             

             

             

             

             

             

             

                   這就是說,在編譯階段,各個(gè)文件中定義的全局變量相互是透明的,編譯A時(shí)覺察不到B中也定義了i,同樣,編譯B時(shí)覺察不到A中也定義了i

            但是到了鏈接階段,要將各個(gè)文件的內(nèi)容“合為一體”,因此,如果某些文件中定義的全局變量名相同的話,在這個(gè)時(shí)候就會出現(xiàn)錯(cuò)誤,也就是上面提示的重復(fù)定義的錯(cuò)誤。

                   因此,各個(gè)文件中定義的全局變量名不可相同。

             

             

                  

                   在鏈接階段,各個(gè)文件的內(nèi)容(實(shí)際是編譯產(chǎn)生的obj文件)是被合并到一起的,因而,定義于某文件內(nèi)的全局變量,在鏈接完成后,它的可見范圍被擴(kuò)大到了整個(gè)程序。

                   這樣一來,按道理說,一個(gè)文件中定義的全局變量,可以在整個(gè)程序的任何地方被使用,舉例說,如果A文件中定義了某全局變量,那么B文件中應(yīng)可以該變量。修改我們的程序,加以驗(yàn)證:

            //A.cpp

             

             

             

             

            void main()

             

             

            {

             

             

                i = 100; //試圖使用B中定義的全局變量

             

             

            }

             

             

             

             

             

             

             

             

             

             

             

             

            //B.cpp

             

             

            int i;

             

             

             

             

             

             

             

             

                   編譯結(jié)果如下:

             

             

                  

            Compiling...

             

             

            A.cpp

             

             

            C:\Documents and Settings\wangjian\桌面\try extern\A.cpp(5) : error C2065: 'i' : undeclared identifier

             

             

            Error executing cl.exe.

             

             

             

             

            A.obj - 1 error(s), 0 warning(s)

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

                   編譯錯(cuò)誤。

                   其實(shí)出現(xiàn)這個(gè)錯(cuò)誤是意料之中的,因?yàn)椋何募卸x的全局變量的可見性擴(kuò)展到整個(gè)程序是在鏈接完成之后,而在編譯階段,他們的可見性仍局限于各自的文件。

                   編譯器的目光不夠長遠(yuǎn),編譯器沒有能夠意識到,某個(gè)變量符號雖然不是本文件定義的,但是它可能是在其它的文件中定義的。

                  

                   雖然編譯器不夠遠(yuǎn)見,但是我們可以給它提示,幫助它來解決上面出現(xiàn)的問題。這就是extern的作用了。

                   extern的原理很簡單,就是告訴編譯器:“你現(xiàn)在編譯的文件中,有一個(gè)標(biāo)識符雖然沒有在本文件中定義,但是它是在別的文件中定義的全局變量,你要放行!”

                   我們?yōu)樯厦娴腻e(cuò)誤程序加上extern關(guān)鍵字:

            //A.cpp

             

             

             

             

            extern int i;

             

             

            void main()

             

             

            {

             

             

                i = 100; //試圖使用B中定義的全局變量

             

             

            }

             

             

             

             

             

             

             

             

             

             

             

             

             

             

            //B.cpp

             

             

            int i;

             

             

             

             

             

             

             

             

                   順利通過編譯,鏈接。

             

             

             

             

            2、 C++文件中調(diào)用C方式編譯的函數(shù)

             

             

             

             

            C方式編譯和C++方式編譯

            相對于CC++中新增了諸如重載等新特性,對于他們的編譯,必然有一些重要的區(qū)別。

            我們將下面的小程序分別按CC++方式編譯,來探討兩種編譯方式的區(qū)別。

            int i;

             

             

             

             

            int func(int t)

             

             

            {

             

             

                     return 0;

             

             

            }

             

             

             

             

            void main()

             

             

            {

             

             

            }

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

                   C方式編譯的結(jié)果:

            COMM     _i  :  DWORD

             

             

             

             

            PUBLIC    _func

             

             

             

             

            PUBLIC    _main

             

             

             

             

             

             

             

             

             

             

             

             

                   C++方式編譯的結(jié)果:

            PUBLIC    ?i@@3HA                                               ; i

             

             

             

             

            PUBLIC    ?func@@YAHH@Z                                         ; func

             

             

             

             

            PUBLIC    _main

             

             

             

             

             

             

             

             

             

             

             

             

                   可見,C方式編譯下,變量名和函數(shù)名之前被統(tǒng)一加上了一個(gè)下劃線,而C++編譯后的結(jié)果卻復(fù)雜的多,i變成了?i@@3HAfunc變成了?func@@YAHH@ZC++中的這種看似復(fù)雜的命名規(guī)則是為C++中的函數(shù)重載,參數(shù)檢查等特性服務(wù)的。

             

             

             

             

            多文件程序中的函數(shù)調(diào)用

             

             

                   一般情況下,工程中的文件都是CPP文件(以及頭文件)。如下面的程序僅包含兩個(gè)文件:A.CPPB.CPP

             

             

            //A.CPP

             

             

            void func();

             

             

             

             

            void main()

             

             

            {

             

             

                     func();

             

             

            }

             

             

             

             

             

             

             

             

             

             

             

             

             

             

            //B.CPP

             

             

            void func()

             

             

            {

             

             

            }

             

             

             

             

             

             

             

             

             

             

                   程序的結(jié)構(gòu)是這樣的:在文件B.CPP中定義了一個(gè)函數(shù)void func()main函數(shù)位于文件A.CPP,在main函數(shù)中調(diào)用了B中定義的函數(shù)func()

                   要在A中調(diào)用B中定義的函數(shù),必須要加上該函數(shù)的聲明。如本例中的void func();就是對函數(shù)func()的聲明。

            如果沒有聲明的話,編譯A.CPP時(shí)就會出錯(cuò)。因?yàn)榫幾g器的目光只局限于被編譯文件,必須通過加入函數(shù)聲明來告訴編譯器:“某個(gè)函數(shù)是定義在其它的文件中的,你要放行!”,這一點(diǎn)跟用extern來聲明外部全局變量是一個(gè)道理。

                   需要注意的是,一般的程序都是通過包含頭文件來完成函數(shù)的聲明。拿本例來說,一般是創(chuàng)建一個(gè)頭文件B.H,在頭文件中加入聲明語句void func(); 并且在A.CPP中加入包含語句:#include “B.H”

             

             

                   C++程序中,頭文件的功能從函數(shù)聲明被擴(kuò)展為類的定義。

             

             

             

             

            不同編譯方式下的函數(shù)調(diào)用

                   如果在工程中,不僅有CPP文件,還有以C方式編譯的C文件,函數(shù)調(diào)用就會有一些微妙之處。我們將B.CPP改作B.C

             

             

             

             

             

             

            //A.CPP

             

             

            void func();

             

             

             

             

            void main()

             

             

            {

             

             

                     func();

             

             

            }

             

             

             

             

             

             

             

             

             

             

             

             

             

             

            //B.C

             

             

            void func()

             

             

            {

             

             

            }

             

             

             

             

             

             

             

             

             

             

                   A.CPPB.C分別編譯,都沒有問題,但是鏈接時(shí)出現(xiàn)錯(cuò)誤。

            Linking...

             

             

            A.obj : error LNK2001: unresolved external symbol "void __cdecl func(void)" (?func@@YAXXZ)

             

             

            Debug/A.exe : fatal error LNK1120: 1 unresolved externals

             

             

            Error executing link.exe.

             

             

             

             

            A.exe - 2 error(s), 0 warning(s)

             

             

             

             

             

             

             

             

             

             

             

             

            原因就在于不同的編譯方式產(chǎn)生的沖突。

             

             

                   對于文件A,是按照C++的方式進(jìn)行編譯的,其中的func()調(diào)用被編譯成了

            call    ?func1@@YAXXZ    

             

             

             

             

             

             

            如果B文件也是按照C++方式編譯的,那么B中的func函數(shù)名也會被編譯器改成?func1@@YAXXZ,這樣的話,就沒有任何問題。

                   但是現(xiàn)在對B文件,是按照C方式編譯的,B中的func函數(shù)名被改成了_func,這樣一來,A中的call ?func1@@YAXXZ這個(gè)函數(shù)調(diào)用就沒有了著落,因?yàn)樵阪溄悠骺磥恚?/span>B文件中沒有名為?func1@@YAXXZ的函數(shù)。

                   事實(shí)是,我們編程者知道,B文件中有A中調(diào)用的func函數(shù)的定義,只不過它是按照C方式編譯的,故它的名字被改成了_func。因而,我們需要通過某種方式告訴編譯器:“B中定義的函數(shù)func()經(jīng)編譯后命名成了_func,而不是?func1@@YAXXZ,你必須通過call _func來調(diào)用它,而不是call ?func1@@YAXXZ。”簡單的說,就是告訴編譯器,調(diào)用的func()函數(shù)是以C方式編譯的,fun();語句必須被編譯成call _func;而不是call ?func1@@YAXXZ

                  

                   我們可以通過extern關(guān)鍵字,來幫助編譯器解決上面提到的問題。

                   對于本例,只需將A.CPP改成如下即可:

            //A.CPP

             

             

            extern "C"

             

             

            {

             

             

                     void func();

             

             

            }

             

             

            void main()

             

             

            {

             

             

                     func();

             

             

            }

             

             

             

             

                  

             

             

             

             

             

             

             

             

             

             

             

             

                   察看匯編代碼,發(fā)現(xiàn)此時(shí)的func();語句被編譯成了call _func

            3、 補(bǔ)充

             

             

            2一樣,仍然是CC++混合編程的情形,考慮下面的程序:

            //A.CPP

             

             

             

             

            extern int i;

             

             

             

             

            void main()

             

             

            {

             

             

                     i = 100;

             

             

            }

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

            //B.C

             

             

            int i;

             

             

             

             

             

             

                   程序很簡單:在文件B.C中定義了一個(gè)全局變量i,在A.CPP中使用了這個(gè)全局變量。

                   編譯沒有問題,鏈接時(shí)卻出現(xiàn)錯(cuò)誤:

            Linking...

             

             

            A.obj : error LNK2001: unresolved external symbol "int i" (?i@@3HA)

             

             

            Debug/A.exe : fatal error LNK1120: 1 unresolved externals

             

             

            Error executing link.exe.

             

             

             

             

            A.exe - 2 error(s), 0 warning(s)

             

             

             

             

             

             

             

             

             

             

             

             

                  

                   這是因?yàn)椋?/span>C方式編譯下,i被重命名為_i,而在C++方式下,i會被重命名為?i@@3HA

             

             

            因而,我們只用extern int i;來聲明還不夠,必須告訴編譯器,全局變量i是以C方式編譯的,

             

             

            它會被重命名為_i,而不是?i@@3HA

             

             

             

             

                   我們修改A.CPP,如下:

             

             

            //A.CPP

             

             

             

             

            extern "C"

             

             

            {

             

             

                     int i;

             

             

            }

             

             

            void main()

             

             

            {

             

             

             

             

                     i = 100;

             

             

            }

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

             

                   程序正常通過編譯和鏈接。

             

             

                   我們察看一下匯編代碼,發(fā)現(xiàn)語句i = 100;被編譯成了mov  DWORD PTR _i, 100

            posted on 2008-08-25 01:20 葉子 閱讀(304) 評論(0)  編輯 收藏 引用 所屬分類: C\C++

            一本久久综合亚洲鲁鲁五月天| 亚洲精品乱码久久久久久久久久久久 | 欧美精品乱码99久久蜜桃| 婷婷久久综合九色综合绿巨人| 久久久久久久久66精品片| 久久人妻少妇嫩草AV蜜桃| 久久人妻少妇嫩草AV蜜桃| 99re这里只有精品热久久| 蜜桃麻豆www久久国产精品| 伊人久久大香线蕉av一区| 国产一区二区精品久久凹凸| 久久精品中文无码资源站| 亚洲综合久久综合激情久久| yy6080久久| 久久国产成人亚洲精品影院| 色偷偷偷久久伊人大杳蕉| 久久久久国色AV免费看图片| 久久国产精品久久国产精品| 97视频久久久| 开心久久婷婷综合中文字幕| www.久久热| 久久国产精品77777| 伊人久久大香线蕉亚洲| 色天使久久综合网天天| 久久福利片| 国产精品久久久久久久午夜片| 国产精品久久久久AV福利动漫 | 久久精品国产WWW456C0M| 国产成人精品白浆久久69| 国产成人精品综合久久久久 | 亚洲综合伊人久久综合| 亚洲精品成人网久久久久久| 国产福利电影一区二区三区久久久久成人精品综合 | 亚洲国产成人久久精品99| 91精品国产91久久久久久| 久久精品国产亚洲网站| 99久久777色| 99久久婷婷国产综合精品草原| 国产精品久久99| 日本久久久精品中文字幕| 色综合久久综精品|