2019-09-22存儲(chǔ)類&作用域&生命周期&鏈接屬性

1.概念解析

1.1、存儲(chǔ)類

(1)存儲(chǔ)類就是存儲(chǔ)類型,也就是描述C語(yǔ)言變量在何種地方存儲(chǔ)。
(2)內(nèi)存有多種管理方法:棧、堆、數(shù)據(jù)段、bss段、text段等,一個(gè)變量的存儲(chǔ)類型屬性就是描述這個(gè)變量存儲(chǔ)在何種內(nèi)存段中的。
(3)比如:局部變量分配在棧上,所以它的存儲(chǔ)類就是棧;顯式初始化為非零的全局變量分配在數(shù)據(jù)段,顯式初始化為0和沒有顯式初始化(默認(rèn)為0)的全局變量分配在bss段,也就是存儲(chǔ)在哪,存儲(chǔ)類就是哪。

1.2、作用域

(1)作用域是描述這個(gè)變量起作用的代碼范圍。
(2)基本來說,C語(yǔ)言變量的作用域規(guī)則是代碼塊作用域。意思就是這個(gè)變量起作用的范圍是當(dāng)前的代碼塊。代碼塊就是一對(duì)大括號(hào){}括起來的范圍,所以一個(gè)變量的作用域是:這個(gè)變量定義所在的{}范圍內(nèi)從這個(gè)變量定義開始往后的部分。

1.3、生命周期

(1)生命周期是描述這個(gè)變量什么時(shí)候誕生(運(yùn)行時(shí)分配內(nèi)存空間給這個(gè)變量)及什么時(shí)候消亡,(運(yùn)行時(shí)收回這個(gè)內(nèi)存變量,此后再不能訪問這個(gè)內(nèi)存地址,或者訪問這個(gè)內(nèi)存地址已經(jīng)和這個(gè)變量無關(guān)了)。
(2)變量和內(nèi)存的關(guān)系,就和人(變量)去圖書館借書(內(nèi)存)一樣。變量的生命周期就好像是我人借書的這段周期一樣。
(3)研究變量的生命周期可以幫助我們理解程序的一些現(xiàn)象、理解C語(yǔ)言的一些規(guī)則。

1.4、鏈接屬性

(1)大家知道程序從源代碼到最終可執(zhí)行程序,經(jīng)歷的過程:編譯、鏈接。
(2)編譯階段就是把源代碼轉(zhuǎn)換成.o目標(biāo)文件,目標(biāo)文件里面有很多符號(hào)和代碼段、數(shù)據(jù)段、bss段等分段。符號(hào)就是編程中的變量名、函數(shù)名等。運(yùn)行時(shí)變量名、函數(shù)名能夠和相應(yīng)的內(nèi)存對(duì)應(yīng)起來,靠符號(hào)來做鏈接的。
(3).o的目標(biāo)文件鏈接生成最終可行性程序的時(shí)候,其實(shí)就是把符號(hào)和相對(duì)應(yīng)的段給鏈接起來。C語(yǔ)言中的符號(hào)有三種鏈接屬性:外鏈接屬性、內(nèi)鏈接屬性、無鏈接屬性。

2.Linux下C程序的內(nèi)存映像

2.1、代碼段、只讀數(shù)據(jù)段

(1)對(duì)應(yīng)著程序中的代碼(函數(shù)),代碼段在Linux中又叫文本段(.text)。
(2)只讀數(shù)據(jù)段就是在程序運(yùn)行期間只能讀不能寫的數(shù)據(jù)段,const修飾的常量有可能存在只讀數(shù)據(jù)段的(但是不一定,const常量的實(shí)現(xiàn)方法在不同平臺(tái)是不一樣的)。

2.2、數(shù)據(jù)段、bss段

(1)數(shù)據(jù)段存:①顯式初始化為非0的全局變量;②顯式初始化為非0的static的局部變量。
(2)bss段存:①顯式初始化為0或者未顯式初始化的全局變量;②顯式初始化為0或者未顯式初始化的static局部變量。

2.3、堆

C語(yǔ)言中什么樣的變量存在堆內(nèi)存中?
C語(yǔ)言不會(huì)自動(dòng)向堆中存放東西,堆的操作是程序員自己手工操作的。程序員根據(jù)需求自己判斷要不要使用堆內(nèi)存,用的時(shí)候自己申請(qǐng),自己使用完了,自己釋放。

2.4、文件映射區(qū)

文件映射區(qū)就是進(jìn)程打開了文件后,將這個(gè)文件的內(nèi)容從硬盤讀到進(jìn)程的文件映射區(qū),以后就直接在內(nèi)存中操作這個(gè)文件,讀寫完了后再保存時(shí)再將內(nèi)存中的文件寫到硬盤中去。

2.5、棧

棧內(nèi)存區(qū),局部變量分配在棧上;函數(shù)調(diào)用傳參過程也會(huì)用到棧。

2.6、內(nèi)核映射區(qū)

(1)內(nèi)核映射區(qū)就是將操作系統(tǒng)內(nèi)核程序映射到這個(gè)區(qū)域里。
(2)對(duì)于Linux中的每一個(gè)進(jìn)程來說,它都以為整個(gè)系統(tǒng)中只有它自己和內(nèi)核而已。它認(rèn)為內(nèi)存地址0xc0000000以下的都是自己的活動(dòng)空間,0xc0000000以上的是OS內(nèi)核活動(dòng)空間。
(3)每一個(gè)進(jìn)程都活在自己獨(dú)立的進(jìn)程空間中,0-3G的空間每一個(gè)進(jìn)程是不同的(因?yàn)橛昧颂摂M地址技術(shù)),但是內(nèi)核是唯一的。

2.7、OS下和裸機(jī)下C程序加載執(zhí)行的差異

(1)C語(yǔ)言運(yùn)行時(shí)環(huán)境有一定的要求,意思就是單獨(dú)個(gè)人寫的C語(yǔ)言程序沒法直接在內(nèi)存中運(yùn)行,需要外部一定的協(xié)助,這段協(xié)助代碼叫加載運(yùn)行代碼(或者叫構(gòu)建C運(yùn)行時(shí)環(huán)境的代碼,這一段代碼在操作系統(tǒng)下是別人寫好的,會(huì)自動(dòng)添加到我們寫的程序上,這段代碼的作用主要是:給全局變量賦值、清bss段)。
(2)在ARM裸機(jī)上寫shell時(shí)定義了一個(gè)全局變量初始化為0但是實(shí)際不為0,后來在裸機(jī)的start.c中加了清bss段代碼后就為0了。這就說明在裸機(jī)程序中沒人幫我們來做這一段加載運(yùn)行時(shí)代碼,要程序與自己做(start.c中的重定位和清bss段就是在做這個(gè)事);在操作系統(tǒng)中運(yùn)行程序時(shí)程序員自己不用操心,會(huì)自動(dòng)完成重定位和清bss,所以我們看到的現(xiàn)象:C語(yǔ)言中未初始化的全局變量默認(rèn)為0.
(3)數(shù)據(jù)段的全局變量或靜態(tài)局部變量都是有非0的初值的,這些初值在main函數(shù)運(yùn)行之前就已經(jīng)被初始化了,是重定位期間完成的初始化。

3.存儲(chǔ)類相關(guān)的關(guān)鍵字1

3.1、auto

(1)auto關(guān)鍵字在C語(yǔ)言中只有一個(gè)作用,那就是修飾局部變量。
(2)auto修飾局部變量,表示這個(gè)局部變量是自動(dòng)局部變量,自動(dòng)局部變量分配在棧上(既然在棧上,說明如果它不初始化那么值是隨機(jī)的)。
(3)平時(shí)定義局部變量時(shí)就是定義auto,只是省略了auto關(guān)鍵字而已。課件,auto的局部變量其實(shí)就是默認(rèn)定義的普通局部變量。

3.2、static

(1)static關(guān)鍵字在C語(yǔ)言中有兩種用法,而且這兩種用法彼此沒有任何關(guān)聯(lián),完全是獨(dú)立的。
(2)第一種:用來修飾局部變量,形成靜態(tài)局部變量。要搞清楚靜態(tài)局部變量和非靜態(tài)局部變量的區(qū)別。本質(zhì)區(qū)別是存儲(chǔ)類不同(存儲(chǔ)類不同就衍生出很多不同);非靜態(tài)局部變量分配在棧上,而靜態(tài)局部變量分配在數(shù)據(jù)段/bss段上。
(3)第二種:用來修飾全局變量,形成靜態(tài)全局變量。要搞清楚靜態(tài)全局變量和非靜態(tài)全局變量的區(qū)別,區(qū)別是在鏈接屬性上不同,后面詳細(xì)講。
(4)分析:
①靜態(tài)局部變量在存儲(chǔ)類方面和全局變量一樣。
②靜態(tài)局部變量和全局變量的區(qū)別是:作用域、鏈接屬性。靜態(tài)局部變量作用域是代碼塊作用域(和普通局部變量是一樣的)、鏈接屬性是無鏈接;全局變量作用域是文件作用域(和函數(shù)一樣)、鏈接屬性是外鏈接。

3.3、register

(1)register關(guān)鍵字不常用,也只有一個(gè)作用,那就是:register修飾的變量(一般是全局變量)編譯器會(huì)盡量將它分配在寄存器中。(平時(shí)分配的一般的變量都是在內(nèi)存中的)。分配在寄存器中一樣的用,但是讀寫效率會(huì)高很多。所以register修飾的變量用在那種變量被反復(fù)高頻率的使用,通過改善這個(gè)變量的訪問效率可以極大的提升程序運(yùn)行效率時(shí)。所以register是一種極致提升程序運(yùn)行效率的手段。
(2)uboot中用到了一個(gè)register類型的變量,gd這個(gè)變量是用來存uboot的全局變量(gd就是global data)。因?yàn)檫@個(gè)全局變量在整個(gè)uboot中到處都被訪問,所以定義成register的。
(3)平時(shí)寫代碼要定義成register這種情況很少,一般慎用。
(4)register編譯器只能承諾盡量將register修飾的變量放在寄存器中,但是不保證一定放在寄存器中。主要原因是因?yàn)榧拇嫫鲾?shù)量有限,不一定有空用。

4.存儲(chǔ)類相關(guān)的關(guān)鍵字2

4.1、extern

(1)extern主要用來聲明全局變量,聲明的目的主要是在a.c中定義全局變量(extern int a;)而在b.c中使用該變量。
(2)C語(yǔ)言中程序的編譯時(shí)以單個(gè).c源文件為單位的,因此編譯a.c時(shí)只考慮a.c中的內(nèi)容(不會(huì)考慮 b.c的內(nèi)容),這就導(dǎo)致a.c中使用了b.c中定義的變量時(shí)在編譯時(shí)報(bào)錯(cuò)。解決方案是聲明。
(3)應(yīng)該在a.c中使用g_b之前先聲明g_b,并且它的原型和聲明的一樣,將來在鏈接的時(shí)候鏈接器會(huì)在.o文件中找到這個(gè)同名變量。聲明一個(gè)全局變量就要用到extern關(guān)鍵字。

4.2、volatile

(1)volatile的字面意思:可變的、易變的。C語(yǔ)言中volatile用來修飾一個(gè)變量,表示這個(gè)變量可以被編譯器之外的東西改變。編譯器之內(nèi)的意思是變量的值的改變是代碼的作用,編譯器之外的變就是這個(gè)改變不是代碼造成的,或者不是當(dāng)前代碼造成的,編譯器在編譯當(dāng)前代碼時(shí)無法預(yù)知。比如在中斷處理程序isr中更改了這個(gè)變量的值(一般這個(gè)變量是一個(gè)寄存器的值)。
(2)以上說的三種情況(中斷isr中引用的變量,多線程中共用的變量,硬件會(huì)更改的變量)都是編譯器在編譯時(shí)無法預(yù)知的更改,此時(shí)應(yīng)該使用volatile告訴編譯器這個(gè)變量屬于這種(可變的、易變的)情況。編譯器在遇到volatile修飾的變量時(shí)就不會(huì)對(duì)該變量的的訪問進(jìn)行優(yōu)化,就不會(huì)出現(xiàn)錯(cuò)誤。

int a, b, c;
a = 3;
b = a;
c = b;

無優(yōu)化情況下:內(nèi)存要讀取3次,寫3次
編譯器優(yōu)化后:內(nèi)存只要讀1次,寫3次
(3)編譯器的優(yōu)化在一般情況下非常好,可以幫助提升程序效率。但是在特殊情況(volatile)下,變量會(huì)被編譯器想象之外的力量所改變,此時(shí)如果編譯器沒有意識(shí)到而去優(yōu)化則會(huì)造成優(yōu)化錯(cuò)誤,優(yōu)化錯(cuò)誤就會(huì)帶來執(zhí)行時(shí)錯(cuò)誤。而且這種錯(cuò)誤很難被發(fā)現(xiàn)。

volatile int a, b, c;
a = 3;
/* 假設(shè)在這里插入一個(gè)中斷程序,把a(bǔ)改為13,如果a定義時(shí)未加volatile,則a還會(huì)被當(dāng)成3,a=b=c=3;
如果加了volatile,則a =13, b=c=13,也就是加了volatile就是說這個(gè)變量易變,值變了后不用管它,不要去優(yōu)化它。
*/
b = a;
c = b;

4.3、restrict

(1)C99才支持的,所以很多延續(xù)C89的編譯器是不支持restrict關(guān)鍵字的,gcc支持的。
(2)restrict也是和編譯器行為特征相關(guān)的。
(3)restrict只用來修飾指針,不能修飾普通變量。

4.4、typedef

typedef在C語(yǔ)言關(guān)鍵字歸類上屬于存儲(chǔ)類關(guān)鍵字,但是實(shí)際上和存儲(chǔ)類沒有關(guān)系,因?yàn)樗揎椀氖穷愋?,并不占用?nèi)存。

5.作用域詳解

5.1、局部變量的代碼塊作用域

(1)代碼塊基本可以理解為一對(duì)大括號(hào){}括起來的部分;
(2)代碼塊不等于函數(shù),因?yàn)閕f、while、for都有{},所以代碼塊<=函數(shù)。
(3)局部變量的作用域是代碼塊作用域,也就是說一個(gè)局部變量可以被訪問和使用的范圍僅限于定義這個(gè)局部變量的代碼塊中定義式之后的部分。

5.2、函數(shù)名和全局變量的文件作用域

(1)文件作用域的意思就是全局的訪問權(quán)限,也就是說整個(gè).c文件中都可以訪問這些東西。這就是平時(shí)所說的局部和全局,全局就是文件作用域。
(2)詳細(xì)準(zhǔn)確的說:函數(shù)和全局變量的作用域是定義所在的整個(gè).c文件之內(nèi)定義式之后的部分。
(3)總結(jié):
①不管是局部變量、全局變量、函數(shù),都要先定義才能使用。
②嚴(yán)格來說我們上面的總結(jié)是錯(cuò)誤的。準(zhǔn)確的說:全局變量/函數(shù)作用域都是自己所在的文件,但是定義式之前的部分因?yàn)槿鄙俾暶魉詻]法使用。
解決方案是:1)把它定義到前面去;2)定義到后面但是在使用之前加聲明;局部變量因?yàn)闆]法聲明,所以只能定義在前面。
聲明對(duì)全局變量很有用,因?yàn)橐粋€(gè).c源文件上千行代碼,很容易出現(xiàn)函數(shù)先使用而未定義的情況。(extern int a;聲明)
(4)在C89標(biāo)準(zhǔn)的編譯器中(現(xiàn)在很多編譯器還延續(xù)使用C89標(biāo)準(zhǔn)),所有的局部變量必須先定義在最前面,在變量定義之前不能有依據(jù)執(zhí)行代碼。在C99標(biāo)準(zhǔn)的編譯器中(gcc兼容C99標(biāo)準(zhǔn))可以允許在代碼塊任意地方定義變量,但是允許定義的變量還是只能使用在定義了之后,定義之前還是不能用的。

5.3、同名變量的掩蔽規(guī)則

(1)問題:編程時(shí),不可避免會(huì)出現(xiàn)同名變量。變量同名后不一定會(huì)出錯(cuò)。
(2)首先,如果兩個(gè)同名變量作用域不同且沒有交疊,這種情況同名沒有任何影響。
(3)其次,如果兩個(gè)同名變量作用域有交疊,C語(yǔ)言規(guī)定在作用域交疊范圍內(nèi),作用域小的一個(gè)變量會(huì)掩蔽掉作用域大的那個(gè)(縣官不如現(xiàn)管)即局部變量比全局變量影響大。

6.變量的生命周期

6.1、研究變量生命周期的意義

研究變量生命周期,有助于理解變量的行為特征。

6.2、棧變量的生命周期

(1)局部變量(棧變量)存儲(chǔ)在棧上,生命周期是臨時(shí)的,臨時(shí)的意思是說:代碼指向過程中按照需要去創(chuàng)建、使用、消亡的。
(2)比如一個(gè)函數(shù)內(nèi)定義的局部變量,在這個(gè)函數(shù)每一次被調(diào)用時(shí)都會(huì)創(chuàng)建一次,然后使用,最后在函數(shù)返回的時(shí)候消亡。
(3)思考:一個(gè)函數(shù)內(nèi)的局部變量為什么在函數(shù)外不能使用?
(4)思考:局部變量為什么分配在棧上?或者說局部變量為什么是臨時(shí)生命周期?

6.3、堆變量的生命周期

(1)首先要明白:堆內(nèi)存空間是客觀存在的,意思是由操作系統(tǒng)維護(hù)的。我們程序只是去申請(qǐng)然后使用最后釋放。
(2)我們只關(guān)心我們程序使用堆內(nèi)存的這一段時(shí)間,因此堆變量也有了自己的生命周期,就是從malloc申請(qǐng)時(shí)誕生,然后使用,知道free時(shí)消亡。
(3)所以堆內(nèi)存在malloc之前和free之后不能再去訪問,因此堆內(nèi)存在實(shí)踐編程時(shí)都是被反復(fù)使用的malloc和free的。

6.4、代碼段、只讀段的生命周期

(1)其實(shí)就是程序執(zhí)行的代碼,其實(shí)就是函數(shù),它的生命周期是永久的。不過一般代碼的生命周期我們并不關(guān)注。
(2)有時(shí)候放在代碼段的不只是代碼,還有const類型的常量,還有字符串常量。(const類型的常量、字符串常量有時(shí)候放在rodata段,有時(shí)候放在代碼段,取決于平臺(tái))。

7.鏈接屬性

7.1、C語(yǔ)言程序的組織架構(gòu):多個(gè)C文件+多個(gè)h文件

(1)龐大、完整的一個(gè)C語(yǔ)言程序(比如Linux內(nèi)核、uboot)由多個(gè)C文件和多個(gè)h文件組成的。
(2)程序的生成過程就是:編譯+鏈接。編譯時(shí)為了將函數(shù)/變量等變成.o二進(jìn)制的機(jī)器碼格式,鏈接是為了將各個(gè)獨(dú)立分開的二進(jìn)制的函數(shù)鏈接形成一個(gè)整體的二進(jìn)制可執(zhí)行程序。

7.2、編譯以文件為單位、鏈接以工程為單位

(1)編譯器工作時(shí)是將所有源文件依次讀進(jìn)來,單個(gè)為單位進(jìn)行編譯的。
(2)鏈接的時(shí)候?qū)嶋H上是把第一步編譯生成單個(gè).o文件整體的輸入,然后處理鏈接成一個(gè)可執(zhí)行程序。

7.3、三種鏈接屬性:外鏈接、內(nèi)鏈接、無鏈接

(1)外部鏈接的意思就是外部鏈接屬性,也就是說這個(gè)可以在整個(gè)程序范圍內(nèi)(言下之意就是可以跨文件)進(jìn)行鏈接,比如普通的函數(shù)和全局變量屬于外鏈接。
(2)內(nèi)鏈接的意思是(C文件內(nèi)部)內(nèi)部鏈接屬性,也就是說這個(gè)可以在當(dāng)前C文件內(nèi)部范圍內(nèi)進(jìn)行鏈接(言下之意就是不能在當(dāng)前C文件外面其他C文件中進(jìn)行訪問、鏈接)。static修飾的函數(shù)和全局變量屬于內(nèi)鏈接。
(3)無鏈接的意思就是這個(gè)符號(hào)本身不參與鏈接,它跟鏈接沒關(guān)系。所有的局部變量(auto、static的)都是無鏈接的。
總結(jié):外即文件外,內(nèi)即文件內(nèi),鏈接可以理解成訪問。

7.4、函數(shù)或全局變量的同名沖突

(1)因?yàn)楹瘮?shù)和全局變量是外部鏈接屬性,也就是說每一個(gè)函數(shù)和全局變量將來在曾哥程序中所有的C文件都能被訪問,因此在一個(gè)程序中的所有C文件中不能出現(xiàn)同名的函數(shù)/同名的全局變量。
(2)最簡(jiǎn)單的解決方案就是起名字不重復(fù),但是很難做到。主要原因是一個(gè)很大的工程中函數(shù)和全局變量名字太多了,而且一個(gè)大工程不是一個(gè)人完成的,是很多人協(xié)作完成的,所以很難保證不會(huì)重名。解決方案?
(3)現(xiàn)代高級(jí)語(yǔ)言中完美解決這個(gè)問題的方法就是命名空間namespace(其實(shí)就是給一個(gè)變量帶上各個(gè)級(jí)別的前綴)。但是C語(yǔ)言不是這么解決的。
(4)C語(yǔ)言比較早碰到這個(gè)問題,當(dāng)時(shí)還沒發(fā)明namespace這個(gè)概念,當(dāng)時(shí)C語(yǔ)言就發(fā)明了一張不是很完美但是湊合能用的解決方案,就是三種鏈接屬性的方法。
(5)C語(yǔ)言的連接屬性解決重名問題思路是這樣的:我們將明顯不會(huì)在其他C文件中引用(只在當(dāng)前C文件中引用)的函數(shù)/全局變量,使用static修飾,使其成為內(nèi)鏈接屬性,這樣在將來鏈接時(shí)即使2個(gè)C文件a中有重名的函數(shù)或全局變量,只要至少1個(gè)為內(nèi)鏈接屬性就沒事。
(6)這種解決方案在一定程度上解決了問題。但是沒有從根本上解決問題,留下了很多瑪法。所以這個(gè)就是導(dǎo)致C語(yǔ)言寫很大型的項(xiàng)目難度很大。

7.5、static的第二種用法:修飾全局變量和函數(shù)

(1)普通的(非靜態(tài))的函數(shù)/全局變量,默認(rèn)的鏈接屬性是外部的。
(2)static(靜態(tài))的函數(shù)/全局變量,鏈接屬性屬于內(nèi)部鏈接。

7.6、一般用法總結(jié):

思考:為什么static一個(gè)關(guān)鍵字可以有2中完全不同的意思?因?yàn)檫@兩種用法是互斥的。

7.7、最后的總結(jié):

(1)普通(自動(dòng))局部變量分配在棧上,作用域?yàn)榇a塊作用域,生命周期是臨時(shí)的,鏈接屬性為無鏈接。定義時(shí)如果未顯式初始化則其值隨機(jī),變量地址由運(yùn)行時(shí)在棧上分配得到,多次執(zhí)行時(shí)地址不一定相同,函數(shù)不能把該類型變量的地址(指針)作為返回值。
(2)靜態(tài)局部變量的分配在數(shù)據(jù)段/bss段(顯式初始化為非0則在數(shù)據(jù)段,顯式初始化為0或未顯式初始化則在bss段),作用域?yàn)榇a塊作用域,生命周期為永久,鏈接屬性為無鏈接。定義時(shí)如果未顯式初始化則其其值為0,變量地址由運(yùn)行時(shí)環(huán)境在變;靜態(tài)全局變量其實(shí)就是作用域?yàn)榇a塊作用域(同時(shí)鏈接屬性為無鏈接)的全局變量。靜態(tài)局部變量可以改為用全局變量實(shí)現(xiàn)(程序中盡量避免用全局變量,因?yàn)闀?huì)破壞結(jié)構(gòu)性)。
(3)靜態(tài)全局變量/靜函數(shù)和普通全局變量/普通函數(shù)的唯一差別是:static使全局變量/函數(shù)的鏈接屬性由外部鏈接(整個(gè)程序所有文件范圍)轉(zhuǎn)為內(nèi)部鏈接(當(dāng)前C文件內(nèi))。這是為了解決全局變量/函數(shù)的重命名的問題,因此在程序中文件變多之后全局變量/函數(shù)的重命名問題非常嚴(yán)重,將不必要被其他文件引用的全局變量/函數(shù)聲明為static可以很大程度上改善重命名問題,但是仍然未徹底解決。
(4)寫程序盡量避免使用全局變量,尤其是非static類型的全局變量。為保證不會(huì)被其他文件引用的全局變量一定要static修飾。
(5)注意區(qū)分全局變量的定義和聲明。一般規(guī)律如下:①如果定義的而同時(shí)有初始化則一定會(huì)被認(rèn)為是定義;②如果只是定義而沒有被初始化則有可能被編譯器認(rèn)為是定義,也有可能被認(rèn)為是聲明,要具體分析;③如果使用extern則肯定會(huì)被認(rèn)為是聲明。
(6)全局變量應(yīng)該定義在C文件中并且在頭文件中聲明,而不要定義在頭文件中(因?yàn)槿绻x在 頭文件中,則該頭文件被多個(gè)C文件包含時(shí)該全局變量會(huì)重復(fù)定義)。
(7)在b.c中引用a.c中定義的全局變量/函數(shù)有2種方法:①一是在a.h中聲明該函數(shù)/全局變量,然后在b.c中#include <a.h>;②二是在b.c中使用extern顯式聲明要引用的函數(shù)/全局變量。其中第一種方法比較正式。
(8)存儲(chǔ)類決定生命周期,作用域決定鏈接屬性。
(9)宏和include函數(shù)的鏈接屬性為無鏈接。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容