- PHP 7底層設(shè)計(jì)與源碼實(shí)現(xiàn)
- 陳雷等
- 79字
- 2019-01-04 16:53:46
3.1 基本知識(shí)
為了更好地理解PHP 7中zval的實(shí)現(xiàn),本節(jié)先介紹一下相關(guān)的基本知識(shí),包括什么是數(shù)據(jù)類型,PHP 7中都有哪些變量類型,另外會(huì)介紹與變量存儲(chǔ)相關(guān)的堆和棧的基本知識(shí)。
3.1.1 數(shù)據(jù)類型
數(shù)據(jù)類型是一種為了對(duì)數(shù)據(jù)(或數(shù)據(jù)值)進(jìn)行分類而由用戶定義的類型,在數(shù)據(jù)結(jié)構(gòu)中的定義是一個(gè)值集合以及定義在這個(gè)值集合上的一組操作。
基本的數(shù)據(jù)類型有int、double、long、char及各種指針類型。在C語(yǔ)言中,使用變量時(shí),提前定義變量并指定變量類型,而在PHP中變量不需要指定類型,3.2節(jié)將會(huì)講解弱類型的實(shí)現(xiàn)。
C語(yǔ)言的數(shù)據(jù)類型在不同的操作系統(tǒng)中長(zhǎng)度不同,舉個(gè)例子,x86-64系統(tǒng)架構(gòu)下,一個(gè)char類型的數(shù)據(jù)占1個(gè)字節(jié),一個(gè)int類型的數(shù)據(jù)占4個(gè)字節(jié),一個(gè)指針類型的數(shù)據(jù)占8個(gè)字節(jié),一個(gè)long類型的數(shù)據(jù)占8個(gè)字節(jié),可以在gdb下使用sizeof打印驗(yàn)證:
(gdb) p sizeof(char) $1 = 1 (gdb) p sizeof(int) $2 = 4 (gdb) p sizeof(long) $3 = 8 (gdb) p sizeof(char*) $4 = 8 (gdb) p sizeof(void*) $5 = 8
注意
類型所占空間大小與系統(tǒng)架構(gòu)有關(guān),可以使用show architecture來查看:
(gdb) show architecture The target architecture is set automatically (currently i386:x86-64)
也可以使用set architecture i386:x86-64來設(shè)置:
(gdb) set architecture i386:x86-64 The target architecture is assumed to be i386:x86-64
3.1.2 結(jié)構(gòu)體與聯(lián)合體
結(jié)構(gòu)體是使用struct定義的結(jié)構(gòu),比如定義一個(gè)如下的結(jié)構(gòu)體:
struct test{ char a; //1 int b; //4 long c; //8 void* d; //8 int e; //4 char* f; //8 };
在代碼中標(biāo)記了每個(gè)成員的大小,那么結(jié)構(gòu)體的總大小是1+4+8+8+4+8=33嗎?
下面來打印一下:
(gdb) p sizeof(struct test) $1 = 40
為什么是40而不是33呢?這里面涉及結(jié)構(gòu)體對(duì)齊問題,在筆者的機(jī)器上,結(jié)構(gòu)體是按照8字節(jié)對(duì)齊的,那么可以畫出對(duì)齊后占用的字節(jié)數(shù),如圖3-1所示。

圖3-1 結(jié)構(gòu)體
從圖3-1中可看出,雖然char a只占了1字節(jié),int b只占了4字節(jié),但是long c并不是緊跟著b,而是根據(jù)8字節(jié)對(duì)齊后,c和b之間空了3字節(jié)。同樣,char* f和int e之間也空了4字節(jié),因此總大小為40字節(jié)。雖然浪費(fèi)了7字節(jié),但得益于內(nèi)存對(duì)齊,存取速度會(huì)更快。這是結(jié)構(gòu)體對(duì)齊的基礎(chǔ)。
接下來討論一下聯(lián)合體(union),聯(lián)合體的定義跟結(jié)構(gòu)體類似,定義一個(gè)如下的聯(lián)合體:
union test{ char a; //1 int b; //4 long c; //8 };
同樣打印一下這個(gè)聯(lián)合體的大?。?/p>
(gdb) p sizeof(union test) $1 = 8
那么聯(lián)合體是怎樣的一種格式呢?它復(fù)用了同一塊內(nèi)存,如圖3-2所示。

圖3-2 聯(lián)合體
從圖中可以看出,a、b和c共用同一塊內(nèi)存,修改a,也會(huì)影響b和c的值,同時(shí)可以知道聯(lián)合體的大小為其最大成員的大小,比如圖3-2中聯(lián)合體test的大小為其最大的成員long c的大小,也就是8。
這里簡(jiǎn)單學(xué)習(xí)了結(jié)構(gòu)體和聯(lián)合體的區(qū)別,以及結(jié)構(gòu)體的對(duì)齊,接下來再回顧一下程序執(zhí)行時(shí)的堆和棧相關(guān)的基本知識(shí)。
注意
聯(lián)合體是成員變量共享一塊內(nèi)存,可以根據(jù)使用確定含義;而結(jié)構(gòu)體是不共享的,成員變量不共享一塊內(nèi)存。另外,結(jié)構(gòu)體存在對(duì)齊問題。
3.1.3 堆和棧的基本知識(shí)
程序執(zhí)行時(shí)的內(nèi)存布局主要如下:

圖3-3 程序的堆和棧
1)棧區(qū)(stack)——存儲(chǔ)參數(shù)值、局部變量,維護(hù)函數(shù)調(diào)用關(guān)系等。
2)堆區(qū)(heap)——?jiǎng)討B(tài)內(nèi)存區(qū)域,隨時(shí)申請(qǐng)和釋放,程序自身要對(duì)內(nèi)存泄漏負(fù)責(zé)。
3)全局區(qū)(靜態(tài)區(qū))——存儲(chǔ)全局和靜態(tài)變量。
4)字面量區(qū)——常量字符串存儲(chǔ)區(qū)。
5)程序代碼區(qū)——存儲(chǔ)二進(jìn)制代碼。
程序的堆和棧如圖3-3所示。
接下來寫一段C代碼來理解一下各變量分別存在哪個(gè)段區(qū),代碼如下:
int a=0; //全局初始化區(qū) char *p1; //全局未初始化區(qū) main() { static int b=0; //全局(靜態(tài))初始 化區(qū) int c; //棧 char d[]="abc"; //棧 char *p2; //棧 char *p3 = "hello"; //hello\0在常量區(qū),p3在棧上 p1 = (char*)malloc(10); p2 = (char*)malloc(20); //分配得來的10和20字節(jié)的區(qū)域就在堆區(qū) strcpy(p1, "hello"); //hello\0放在常量區(qū),編譯器可能會(huì)將它與p3所指向的"hello"優(yōu)化成 一個(gè)地方 }
總體來講,棧上的變量是局部的,隨著局部空間的銷毀而銷毀,由系統(tǒng)負(fù)責(zé)。。
堆上的變量可以提供全局訪問,需要自行處理其生命周期。
這一節(jié)學(xué)習(xí)了數(shù)據(jù)類型、結(jié)構(gòu)體、聯(lián)合體,以及程序運(yùn)行時(shí)的堆和棧信息等基本知識(shí),接下來討論一下PHP中的變量。
- UI圖標(biāo)創(chuàng)意設(shè)計(jì)
- 樂高機(jī)器人設(shè)計(jì)技巧:EV3結(jié)構(gòu)設(shè)計(jì)與編程指導(dǎo)
- 實(shí)戰(zhàn)Java程序設(shè)計(jì)
- SEO智慧
- Learning Python Design Patterns
- Linux:Embedded Development
- WordPress 4.0 Site Blueprints(Second Edition)
- Kivy Cookbook
- R數(shù)據(jù)科學(xué)實(shí)戰(zhàn):工具詳解與案例分析
- 寫給程序員的Python教程
- Unity 2018 Augmented Reality Projects
- C語(yǔ)言程序設(shè)計(jì)實(shí)踐
- Python第三方庫(kù)開發(fā)應(yīng)用實(shí)戰(zhàn)
- Access數(shù)據(jù)庫(kù)應(yīng)用教程(2010版)
- jQuery Essentials