關(guān)于內(nèi)存對(duì)齊匪煌,看我

先來看一下這個(gè)例子:

// 64位系統(tǒng)
#include<stdio.h>

struct{
    int  a;
    char b;
}s;

int main ()
{
    printf ("%d\n",sizeof(s);  
    return 0;
}

理論上,64位系統(tǒng)下党巾,int占 4個(gè)byte萎庭,char占 1個(gè)byte,那么將它們放到一個(gè)結(jié)構(gòu)體中應(yīng)該占 4+1 = 5byte齿拂;但是實(shí)際上驳规,通過運(yùn)行程序得到的結(jié)果是 8byte,這就是內(nèi)存對(duì)齊所導(dǎo)致的创肥。

注:本文討論的內(nèi)容均是在64位系統(tǒng)下。

大綱

  • 什么是內(nèi)存對(duì)齊

  • 為什么要內(nèi)存對(duì)齊

  • 內(nèi)存對(duì)齊規(guī)則

一、什么是內(nèi)存對(duì)齊

計(jì)算機(jī)中內(nèi)存空間是按照byte劃分的叹侄,從理論上講似乎對(duì)任何類型的變量的訪問可以從任何地址開始巩搏,但實(shí)際情況是:在訪問特定類型變量的時(shí)候通常在特定的內(nèi)存地址訪問,這就需要對(duì)這些數(shù)據(jù)在內(nèi)存中存放的位置有限制趾代,各種類型數(shù)據(jù)按照一定的規(guī)則在空間上排列贯底,而不是順序的一個(gè)接一個(gè)的排放,這就是對(duì)齊撒强。

內(nèi)存對(duì)齊是編譯器的管轄范圍禽捆。表現(xiàn)為:編譯器為程序中的每個(gè)“數(shù)據(jù)單元”安排在適當(dāng)?shù)奈恢蒙稀?/p>

二、為什么要內(nèi)存對(duì)齊

為了解釋這個(gè)問題飘哨,我們先要了解一下處理器是如何讀取內(nèi)存的胚想?

我們?nèi)绻褍?nèi)存看做是簡(jiǎn)單的字節(jié)數(shù)組,比如在C語言中芽隆,char *就可表示一塊內(nèi)存浊服。那么或許我們會(huì)認(rèn)為,它的內(nèi)存讀取方式可以按照1byte順序讀取胚吁,如下圖牙躺。

howProgrammersSeeMemory

然而,盡管內(nèi)存是以字節(jié)為單位腕扶,但是大部分處理器并不是按字節(jié)塊來存取內(nèi)存的孽拷,這取決于數(shù)據(jù)類型和處理器的設(shè)置;它一般會(huì)以雙字節(jié),四字節(jié),8字節(jié),16字節(jié)甚至32字節(jié)的來存取內(nèi)存半抱,我們將上述這些存取單位稱為內(nèi)存存取粒度.

howProcessorsSeeMemory

現(xiàn)在我們知道脓恕,計(jì)算機(jī)的處理器是以一定大小的塊來進(jìn)行讀取的,這作為我們的前提條件代虾,那么為了解釋為什么要內(nèi)存對(duì)齊进肯?我們不妨先看一看不對(duì)齊的情況會(huì)出現(xiàn)什么問題?

對(duì)齊跟數(shù)據(jù)在內(nèi)存中的位置有關(guān)棉磨。如果一個(gè)變量的內(nèi)存地址剛好位于它本身長(zhǎng)度的整數(shù)倍江掩,他就被稱做自然對(duì)齊。例如一個(gè)整型變量(占4字節(jié))的地址為0x00000016乘瓤,那它就是自然對(duì)齊的环形。

現(xiàn)在假設(shè)一個(gè)整型變量(4字節(jié))不是自然對(duì)齊的,它的起始地址落在0x00000002(圖中藍(lán)色區(qū)域)衙傀,處理器想要訪問它的值抬吟,按照4字節(jié)的塊進(jìn)行讀取,從圖中的0x0起讀统抬,讀取4字節(jié)大小火本,讀到0x3

這樣的一次讀取之后危队,我們并不能取到我們要訪問的整型數(shù)據(jù),緊接著處理器會(huì)繼續(xù)再往下讀钙畔,偏移4個(gè)字節(jié)茫陆,從0x4開始,讀到0x7

到這里擎析,處理器才能讀取到了我們需要訪問的內(nèi)存數(shù)據(jù)簿盅,當(dāng)然這中間還存在剔除與合并的過程。

所以揍魂,在此例中桨醋,當(dāng)整型變量起始地址落在0x2時(shí)(不對(duì)齊),處理器需要兩次讀取才能取到我們要訪問的內(nèi)容现斋。

那如果是對(duì)齊的呢喜最?

顯然,如果是對(duì)齊的步责,對(duì)于本例返顺,僅需讀取1次,我們便可以讀取到目標(biāo)數(shù)據(jù)蔓肯。

可見遂鹊,對(duì)齊與否會(huì)影響到我們的讀取效率。

同時(shí):

各個(gè)硬件平臺(tái)對(duì)存儲(chǔ)空間的處理上有很大的不同蔗包。一些平臺(tái)對(duì)某些特定類型的數(shù)據(jù)只能從某些特定地址開始存取,而不是內(nèi)存中任意地址都是可以讀取的秉扑。

比如有些架構(gòu)的CPU在訪問一個(gè)沒有進(jìn)行對(duì)齊的變量的時(shí)候會(huì)發(fā)生錯(cuò)誤,那么在這種架構(gòu)下編程必須保證字節(jié)對(duì)齊.其他平臺(tái)可能沒有這種情況,但是最常見的是如果不按照適合其平臺(tái)要求對(duì)數(shù)據(jù)存放進(jìn)行對(duì)齊调限,會(huì)在存取效率上帶來損失舟陆。

也正是由于只能在特定的地址處讀取數(shù)據(jù),所以在訪問一些數(shù)據(jù)時(shí)耻矮,對(duì)于訪問未對(duì)齊的內(nèi)存秦躯,處理器可能需要進(jìn)行多次訪問;而對(duì)于對(duì)齊的內(nèi)存裆装,只需要訪問一次就可以踱承。

這就是為什么要內(nèi)存對(duì)齊的原因。

內(nèi)存對(duì)齊不僅便于CPU快速訪問哨免,同時(shí)合理的利用字節(jié)對(duì)齊可以有效地節(jié)省存儲(chǔ)空間茎活。

我們可以同時(shí)對(duì)比一下,不同內(nèi)存存取粒度對(duì)同一任務(wù)的不同影響琢唾。

設(shè)定一個(gè)相同的任務(wù):分別從Address0 和 Address1 中從地址0讀取4個(gè)字節(jié)到處理器的寄存器中载荔。

  • 先看單字節(jié)粒度情況
單字節(jié)內(nèi)存存取粒度

兩圖中左側(cè)表示內(nèi)存,右側(cè)表示寄存器采桃,中間的箭頭表示讀取的過程懒熙。因?yàn)槭菃巫止?jié)存取粒度丘损,讀取內(nèi)存是按照1個(gè)字節(jié)進(jìn)行訪問的,所以對(duì)于Address0 來講工扎,要想從0的位置讀取4個(gè)字節(jié)号俐,需要讀取4次,對(duì)于 Address1 也是一樣的定庵。即使他不是內(nèi)存對(duì)齊的也無妨。

  • 再看雙字節(jié)粒度情況
雙字節(jié)內(nèi)存存取粒度

從Address0 讀取4個(gè)字節(jié)踪危,相比于存取粒度為1字節(jié)的處理器蔬浙,存取次數(shù)變成了一半,只需讀取2次贞远。由于每個(gè)內(nèi)存訪問都需要固定的開銷畴博,因此最小化訪問次數(shù)確實(shí)可以提高性能。同時(shí)Address0 是內(nèi)存對(duì)齊的(數(shù)據(jù)的起始位置落在0的位置上)蓝仲,所以第一次讀取地址01俱病,第二次讀取地址23即可取到目標(biāo)數(shù)據(jù)。

但是袱结,從Address1 讀取時(shí)亮隙。由于該地址未均勻地落在處理器的內(nèi)存訪問邊界上(Address1 中寄存器黑框區(qū)域是該數(shù)據(jù)的內(nèi)存地址區(qū)域,起始位置為1垢夹,不是對(duì)齊的)溢吻,該處理器去取數(shù)據(jù)時(shí),要先從0地址開始讀取第一個(gè)2字節(jié)塊(01)果元,剔除不想要的字節(jié)(0地址)促王,然后從地址2開始讀取下一個(gè)2字節(jié)塊(23),再從地址4開始讀取下一個(gè)2字節(jié)塊(45)而晒,剔除不想要的字節(jié)(地址5)蝇狼。這樣讀取3次之后將最后留下的3塊數(shù)據(jù)合并放入寄存器,才能取到目標(biāo)數(shù)據(jù)倡怎。

  • 四字節(jié)粒度情況呢迅耘?
四字節(jié)內(nèi)存存取粒度

具有四字節(jié)粒度的處理器從Address0 讀取時(shí),可以一次讀取地址0123 就從對(duì)齊的地址中提取四個(gè)字節(jié)诈胜。

然而從Address1 讀取時(shí)豹障,因?yàn)槭遣粚?duì)齊的,讀取地址0123焦匈,剔除0地址血公,繼而讀取地址4567,剔除地址5缓熟、地址6累魔、地址7 摔笤,這樣讀取2次后將留下的2塊數(shù)據(jù)合并放入寄存器,取到目標(biāo)數(shù)據(jù)垦写。

從雙字節(jié)粒度和四字節(jié)粒度中可見吕世,對(duì)于沒有對(duì)齊的內(nèi)存,需要做更多次的讀取與剔除和合并的過程梯投。這顯然是降低效率的命辖。

同時(shí)我們還需要注意到一點(diǎn):對(duì)于對(duì)齊的內(nèi)存,不同的存取粒度也會(huì)影響到存取效率分蓖。粒度小則存取次數(shù)多尔艇,粒度大則浪費(fèi)空間。所以在每個(gè)特定平臺(tái)上的編譯器都有自己的默認(rèn)存取粒度么鹤。

了解了內(nèi)存對(duì)齊以及原因终娃,我們繼續(xù)看一下內(nèi)存對(duì)齊的原則是什么。

三蒸甜、內(nèi)存對(duì)齊規(guī)則

對(duì)于標(biāo)準(zhǔn)數(shù)據(jù)類型

它的地址只要是它的長(zhǎng)度的整數(shù)倍就行了

對(duì)于結(jié)構(gòu)體

在結(jié)構(gòu)體中棠耕,編譯器為結(jié)構(gòu)體的每個(gè)成員按其自然邊界(alignment)分配空間。各個(gè)成員按照它們被聲明的順序在內(nèi)存中順序存儲(chǔ)柠新,第一個(gè)成員的地址和整個(gè)結(jié)構(gòu)體的地址相同窍荧。具體規(guī)則如下:

  • 1.第一個(gè)成員在結(jié)構(gòu)體變量偏移量為0 的地址處,也就是第一個(gè)成員必須從頭開始恨憎。

  • 2.以后每個(gè)成員相對(duì)于結(jié)構(gòu)體首地址的 offset 都是該成員大小的整數(shù)倍搅荞,如有需要編譯器會(huì)在成員之間加上填充字節(jié)。

  • 3.結(jié)構(gòu)體的總大小為 最大對(duì)齊數(shù)的整數(shù)倍(每個(gè)成員變量都有自己的對(duì)齊數(shù))框咙,如有需要編譯器會(huì)在最末一個(gè)成員之后加上填充字節(jié)咕痛。

  • 4.如果嵌套結(jié)構(gòu)體,嵌套的結(jié)構(gòu)體對(duì)齊到自己的最大對(duì)齊數(shù)的整數(shù)倍處喇嘱,結(jié)構(gòu)體的整體大小就是所有最大對(duì)齊數(shù)(包含嵌套結(jié)構(gòu)體的對(duì)齊數(shù))的整數(shù)倍茉贡。

搞個(gè)例子嘗嘗

示例1:

struct test_t {
  int   a;
  long  b;
  short c;
};

第一個(gè)成員為int類型,占4字節(jié)者铜,內(nèi)存分布 00 01 02 03 腔丧;用紅色表示

從結(jié)構(gòu)體的首地址開始將a寫入內(nèi)存

第二個(gè)成員為long類型,占8字節(jié)作烟,此時(shí)內(nèi)存的的偏移量04不是8的整數(shù)倍愉粤,所以要填充字節(jié)(綠色表示填充字節(jié)),到0x7的位置拿撩,然后將long類型的數(shù)據(jù)b寫入內(nèi)存(黃色)

填充4個(gè)字節(jié)并且將b類型寫入內(nèi)存

第三個(gè)成員是short類型衣厘,占2個(gè)字節(jié),此時(shí)內(nèi)存的偏移量16是short類型所占字節(jié)數(shù)的整數(shù)倍,所以直接寫入內(nèi)存(用藍(lán)色表示)

將c寫入內(nèi)存

至此影暴,結(jié)構(gòu)體內(nèi)的數(shù)據(jù)數(shù)據(jù)成員已對(duì)齊错邦,但是當(dāng)前結(jié)構(gòu)體的總大小為18,不滿足規(guī)則3型宙,所以需在最末的成員后面填充6個(gè)字節(jié)撬呢,使其總大小為24。

填充6個(gè)字節(jié)以滿足規(guī)則3

所以 此結(jié)構(gòu)體的所占內(nèi)存大小為24妆兑。

如果將結(jié)構(gòu)體中的short類型與long類型換一下魂拦,

struct test_t {
  int   a;
  short b;
  long  c;
};

會(huì)是一個(gè)什么結(jié)果?我們依然用紅色表示int類型搁嗓,藍(lán)色表示short類型晨另,黃色表示long類型,綠色表示填充字節(jié)谱姓。

更換示例中short與long類型的位置后的結(jié)果

結(jié)果為16∨偾纾可見屉来,對(duì)于成員相同的結(jié)構(gòu)體,如果改變成員的順序狈癞,對(duì)于結(jié)構(gòu)體所占空間的大小是會(huì)產(chǎn)生影響的茄靠,所以,我們不但要了解內(nèi)存對(duì)齊蝶桶,還是正確的利用內(nèi)存對(duì)齊慨绳。

對(duì)于結(jié)構(gòu)體嵌套結(jié)構(gòu)體,在規(guī)則4中已經(jīng)給出真竖,這里的圖就不再畫了脐雪,聰明的你看到這里一定可以得到正確的答案。

我們?cè)賮砘仡櫳厦娴膶?duì)齊規(guī)則:

各成員變量存放的起始地址恢共, 相對(duì)于結(jié)構(gòu)的起始地址的偏移量 战秋,必須為該變量的類型所占用的字節(jié)數(shù)的倍數(shù);

各成員變量在存放的時(shí)候根據(jù)在結(jié)構(gòu)中出現(xiàn)的順序依次申請(qǐng)空間讨韭, 同時(shí)按照上面的對(duì)齊方式調(diào)整位置脂信, 空缺的字節(jié)自動(dòng)填充

同時(shí)為了確保結(jié)構(gòu)的大小為結(jié)構(gòu)的字節(jié)邊界數(shù)(即該結(jié)構(gòu)中占用最大的空間的類型的字節(jié)數(shù))的倍數(shù),所以在為最后一個(gè)成員變量申請(qǐng)空間后 還會(huì)根據(jù)需要自動(dòng)填充空缺的字節(jié)

這就是內(nèi)存對(duì)齊的整體規(guī)則透硝,但仍需注意的是:

在不同架構(gòu)的處理器下狰闪,我們運(yùn)行同一個(gè)示例得到的結(jié)果可能不同,甚至不同的編譯器配置濒生,也會(huì)影響這個(gè)結(jié)果埋泵,我們需要了解影響內(nèi)存對(duì)齊規(guī)則的因素有哪些?

影響內(nèi)存對(duì)齊結(jié)果的因素 罪治?

1.#pragma pack(n)

每個(gè)特定平臺(tái)上的編譯器都有自己的默認(rèn)“對(duì)齊系數(shù)”(也叫對(duì)齊模數(shù))秋泄。程序員可以通過預(yù)編譯命令#pragma pack(n)琐馆,n=1,2,4,8,16來改變這一系數(shù),其中的n就是你要指定的“對(duì)齊系數(shù)”恒序。這里規(guī)定的是上界瘦麸,只影響對(duì)齊單元大于n的成員,對(duì)于對(duì)齊字節(jié)不大于n的成員沒有影響歧胁。

可以認(rèn)為處理器一次性可以從內(nèi)存中讀/寫n個(gè)字節(jié)滋饲。對(duì)于大小小于n的成員,按照自己的對(duì)齊條件對(duì)齊喊巍,因?yàn)椴徽撛趺捶哦伎梢砸淮涡匀〕鐾犁浴?duì)于對(duì)齊條件大于n個(gè)字節(jié)的成員,成員按照自身的對(duì)齊條件對(duì)齊和按照n字節(jié)對(duì)齊需要相同的讀取次數(shù)崭参,但按照n字節(jié)對(duì)齊節(jié)省空間呵曹。

通過預(yù)編譯命令#pragma pack()取消自定義字節(jié)對(duì)齊方式。

也可以寫成:

#pragma pack(push,n)

#pragma pack(pop)

2.__attribute__((aligned (n)))

__attribute__((aligned (n)))何暮,讓所作用的結(jié)構(gòu)成員對(duì)齊在n字節(jié)自然邊界上奄喂。如果結(jié)構(gòu)中有成員的長(zhǎng)度大于n,則按照最大成員的長(zhǎng)度來對(duì)齊海洼。

__attribute__((packed))跨新,取消結(jié)構(gòu)在編譯過程中的優(yōu)化對(duì)齊,按照實(shí)際占用字節(jié)數(shù)進(jìn)行對(duì)齊坏逢。

需要注意的是:內(nèi)存對(duì)齊的 對(duì)齊數(shù) 取決于 對(duì)齊系數(shù) 和 成員的字節(jié)數(shù) 兩者之中的較小值域帐。

舉例說明:

struct test
{
char x1;
short x2;
float x3;
char x4;
}

默認(rèn)情況下,結(jié)構(gòu)的第一個(gè)成員x1,其偏移地址為0是整,占據(jù)了第1個(gè)字節(jié)肖揣。第二個(gè)成員x2為short類型,其起始地址必須2字節(jié)對(duì)界浮入,因此许饿,編譯器在x2和x1之間填充了一個(gè)空字節(jié)。結(jié)構(gòu)的第三個(gè)成員x3和第四個(gè)成員x4恰好落在其自然邊界地址上舵盈,在它們前面不需要額外的填充字節(jié)陋率。在test結(jié)構(gòu)中,成員x3要求4字節(jié)對(duì)齊秽晚,是該結(jié)構(gòu)所有成員中要求的最大邊界單元瓦糟,因而test結(jié)構(gòu)的自然對(duì)齊條件為4字節(jié),編譯器在成員x4后面填充了3個(gè)空字節(jié)赴蝇。整個(gè)結(jié)構(gòu)所占據(jù)空間為12字節(jié)菩浙。

當(dāng)使用:#pragma pack(1) //讓編譯器對(duì)這個(gè)結(jié)構(gòu)作1字節(jié)對(duì)齊

#pragma pack(1) //讓編譯器對(duì)這個(gè)結(jié)構(gòu)作1字節(jié)對(duì)齊
struct test
{
char x1;
short x2;
float x3;
char x4;
};
#pragma pack() //取消1字節(jié)對(duì)齊,恢復(fù)為默認(rèn)4字節(jié)對(duì)齊

這時(shí)候sizeof(struct test)的值為8。

同理:使用__attribute__((packed))

#define PACKED __attribute__((packed))
struct PACKED test
{
char x1;
short x2;
float x3;
char x4;
}test;

這時(shí)候sizeof( test)的值仍為8劲蜻。

總結(jié)

其實(shí)陆淀,內(nèi)存對(duì)齊就是定制了一套規(guī)則,以合理的利用內(nèi)存空間并提高內(nèi)存訪問效率先嬉。
編譯器通過適當(dāng)增加padding轧苫,使每個(gè)成員的訪問都在一個(gè)指令里完成,而不需要多次訪問再拼接疫蔓。
是一個(gè)以空間換時(shí)間的過程含懊。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市衅胀,隨后出現(xiàn)的幾起案子岔乔,更是在濱河造成了極大的恐慌,老刑警劉巖滚躯,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件雏门,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡掸掏,警方通過查閱死者的電腦和手機(jī)茁影,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來阅束,“玉大人,你說我怎么就攤上這事茄唐∠⒙悖” “怎么了?”我有些...
    開封第一講書人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵沪编,是天一觀的道長(zhǎng)呼盆。 經(jīng)常有香客問我,道長(zhǎng)蚁廓,這世上最難降的妖魔是什么访圃? 我笑而不...
    開封第一講書人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮相嵌,結(jié)果婚禮上腿时,老公的妹妹穿的比我還像新娘。我一直安慰自己饭宾,他們只是感情好批糟,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著看铆,像睡著了一般徽鼎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,816評(píng)論 1 290
  • 那天否淤,我揣著相機(jī)與錄音悄但,去河邊找鬼。 笑死石抡,一個(gè)胖子當(dāng)著我的面吹牛檐嚣,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播汁雷,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼净嘀,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了侠讯?” 一聲冷哼從身側(cè)響起挖藏,我...
    開封第一講書人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎厢漩,沒想到半個(gè)月后膜眠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡溜嗜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年宵膨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片炸宵。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡辟躏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出土全,到底是詐尸還是另有隱情捎琐,我是刑警寧澤,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布裹匙,位于F島的核電站瑞凑,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏概页。R本人自食惡果不足惜籽御,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望惰匙。 院中可真熱鬧技掏,春花似錦、人聲如沸项鬼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽秃臣。三九已至涧衙,卻和暖如春哪工,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背弧哎。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工雁比, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人撤嫩。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓偎捎,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親序攘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子茴她,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348