国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

【PHP源碼學習】2019-03-13 PHP字符串筆記

blair / 458人閱讀

摘要:釋放字符串內存空間的時候,需要先釋放指針所指向的內存空間,再釋放結構體本身的內存空間,效率同樣低下,而且這兩個操作順序不能顛倒。如果存了長度,就不會管你是否有,從頭開始讀字符串,一直讀長度為止即可。有些編譯器不支持數組,可將其改成或均可。

baiyan

全部視頻:https://segmentfault.com/a/11...

源視頻地址:http://replay.xesv5.com/ll/24...

字符串的設計過程

在C99的柔性數組標準未發布之前,我們如果想設計一個數據結構,存儲一個字符串,可以很容易地想出如下代碼:

    struct string{
        ...
        int len;   //存長度(至于為什么存長度下文會講到)
        char* val; //存真正的字符串值
    };

那么我們發現,這樣做有如下缺點:

訪問字符串值的時候,需要先訪問結構體,在訪問指針所指向的內存空間,需要2次內存訪問,效率低下。

釋放字符串內存空間的時候,需要先釋放char *val指針所指向的內存空間,再釋放結構體本身的內存空間,效率同樣低下,而且這兩個操作順序不能顛倒。

那么如何改進呢?很容易想到,我們將字符串值和結構體存儲在一片連續的內存空間就可以了。這樣的話,訪問字符串與釋放字符串的內存空間,均僅需1次內存訪問,在C99柔性數組標準發布之前,改進代碼的方式如下:

int main() {

    struct string{
        int len;
    };

    typedef struct string str;

    char *s = "he";
    str *p = (str*)(malloc(sizeof(str) + strlen(s) + 1)); //分配足夠存下一個字符串的結構體
    p->len = strlen(s);
    memcpy(p + 1, s, strlen(s)); //將字符串拷貝到緊鄰結構體的內存處

}

小插曲:這個代碼的第一版,我還出現了一個指針加法的錯誤,見:關于memcpy一個字符串到緊鄰結構體內存空間處的疑問

我們利用gdb調試一下這段代碼:

首先我們應該給這個結構體分配4 + 2 + 1 = 7字節的內存空間,但是由于內存對齊的原因,最終分配了8字節大小的空間。

結構體本身和len字段的地址均是0x602010,len字段的長度為4B,指針加上4B的len字段長度之后,就應該是字符串he的起始地址,即0x602014,將其強轉為char *,發現正好就是我們存的字符串值"he"。注意不是p+4,而是p+1。因為p+4 = p+4*sizeof(指針p的類型)

由于這樣編寫代碼過于繁瑣,所以C99干脆制定一個標準,使用柔性數組代替上述寫法。其實使用的計算方法和上面一段代碼是一樣的,只不過換了一種簡化的寫法而已,這段代碼最終內存中的存儲情況如下:

PHP7中字符串的實現

借助上文講到的字符串數據結構設計思想,PHP中是這樣設計字符串的,它的結構體叫做zend_string:

struct _zend_string {
    zend_refcounted_h gc;         /*引用計數,與垃圾回收相關,暫不展開*/
    zend_ulong        h;          /* 冗余的hash值,計算數組key的哈希值時避免重復計算*/
    size_t            len;        /* 長度 */
    char              val[1];     /* 柔性數組,真正存放字符串值 */
};

第一個問題:為什么要存長度len?不存長度,直接和C語言一樣通過字符串的"