C語言extern作用


筆者:

今天在做電子相冊的實訓的時候,需要arm-linux-gcc main.c Linked.c -o main這樣,然后我在main.c里面定義了一個全局變量,但是在另一個.c文件里面也需要用到,所以老師教我使用了extern,我才發現這東西真的很強大。

以下是copy問題

extern 作用1:聲明外部變量

現代編譯器一般采用按文件編譯的方式,因此在編譯時,各個文件中定義的全局變量是

互相透明的,也就是說,在編譯時,全局變量的可見域限制在文件內部。

 

1

創建一個工程,里面含有A.cppB.cpp兩個簡單的C++源文件:

//A.cpp:

int iRI;

int main()

{

//.....

}

 

//B.cpp

int iRI;

 

gcc A.cpp -c

gcc B.cpp -c

編譯出A.o, B.o都沒有問題。

但當gcc A.o B.o -o test時,

main.o:(.bss+0x0): multiple definition of `iRI'

b.o:(.bss+0x0): first defined here

報錯:重定義。

(但有個非常意外的發現:當同樣的代碼,使用A.c B.c.並使用gcc編譯時,竟然不會報重定義的錯誤,非常不明白是怎么回事。)

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

但是到了鏈接階段,要將各個文件的內容“合為一體”,因此,如果某些文件中定義的全局變量名相同的話,在這個時候就會出現錯誤,也就是上面提示的重復定義的錯誤。因此,各個文件中定義的全局變量名不可相同。

 

但如果用下列方式:在B.cpp中定義iRI;A.cpp中直接使用。則編譯A.cpp時就無法通過。

//A.cpp

int main()

{

iRI=64;

}

 

//B.cpp

int iRI;

 

gcc A.cpp -c

was not declared in this scope.

 

因為編譯器按照文件方式編譯,所以編譯A.cpp時,並不知道B.cpp中定義了iRI

也就是說:文件中定義的全局變量的可見性擴展到整個程序是在鏈接完成之后,而在編譯階段,他們的可見性仍局限於各自的文件。

解決方案如下:

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

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

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

//A.cpp:

extern int iRI;

int main()

{

iRI = 64;

//.....

}

 

//B.cpp

int iRI;

這樣編譯就能夠通過。

extern int iRI; //並未分配空間,只是通知編譯器,在其它文件定義過iRI

 

 

extern 作用2:在C++文件中調用C方式編譯的函數

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

相對於CC++中新增了諸如重載等新特性。所以全局變量和函數名編譯后的命名方式有很大區別。

int a;

int functionA();

對於C方式編譯:

int a;=> _a

int functionA(); => _functionA

對於C++方式編譯:

int a; =>xx@xxx@a

int functionA(); => xx@xx@functionA

可以看出,因為要支持重載,所以C++方式編譯下,生成的全局變量名和函數名復雜很多。與C方式編譯的加一個下划線不同。

於是就有下面幾種情況:

2C++調用C++定義的全局變量

//A.cpp:

extern int iRI;

int main()

{

iRI = 64;

//.....

}

//B.cpp

int iRI;

gcc A.cpp -c

gcc B.cpp -c

gcc A.o B.o -o test

那么在編譯鏈接時都沒問題。

 

3C++調用C定義的全局變量

//A.cpp:

extern int iRI;

int main()

{

iRI = 64;

//.....

}

//B.c

int iRI;

編譯時沒有問題,

gcc A.cpp -c

gcc B.c -c

但鏈接時,gcc B.o A.o -o test

則會報iRI沒有定義。為什么呢?

因為gcc看到A.cpp,就使用C++方式編譯,看到B.c,就使用C方式編譯。

所以在A.cpp中的iRI=>XXX@XXX_iRI;

B.ciRI=_iRI;

所以在鏈接時,A.cpp想找到XXX@XXX_iRI,當然找不到。所以就需要告訴編譯器,iRI是使用C方式編譯的。

//A.cpp:

extern "C"

{

int iRI;

}

int main()

{ iRI = 64;

//.....

}

//B.c

int iRI;

這樣,當編譯A.cpp時,編譯器就知道iRIC方式編譯的。就會使用 _iRI。這樣B.c提供的_iRI就可以被A.cpp找到了。

 

4C++調用C定義的function

//A.cpp

extern int functionA();

 

int main()

{

functionA();

}

 

//B.c

int functionA()

{

//....

}

gcc A.cpp -c

gcc B.c -c

都沒有問題。但同樣的,gcc A.o B.o -o test

則報錯,找不到functionA();

這是因為gccA.cpp認為是C++方式編譯,B.cC方式編譯。

所以functionAB.c中為:_functionA. A.cpp中為:XX@XXX_functionA

所以在鏈接時A.cpp找不到XX@XX_function.

於是需要通知編譯器,functionA()C方式編譯命名的。

//A.cpp

extern "C"

{

int functionA();

}

int main()

{

functionA();

}

 

//B.c

int functionA()

{

//....

}

於是,編譯鏈接都可以通過。

 

總結:

 

extern "C"

{

functionA();

}//不止是聲明,並且還指出:這個function請用C方式編譯。所以不需要再次extern.

extern"C"

{

extern functionA();

}//這樣做沒什么太大意義。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM