c/c++靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)制作

1.什么是庫(kù)

庫(kù)lib是編譯好的二進(jìn)制代碼胎食,可以被操作系統(tǒng)載入內(nèi)存執(zhí)行逗宜,一般是預(yù)先編譯好的函數(shù)的集合庆尘,可以通過(guò)頭文件鏈接到庫(kù)文件剃诅,執(zhí)行已經(jīng)編譯好的代碼段。

庫(kù)一般分為靜態(tài)庫(kù)(static lib驶忌,在linux系統(tǒng)一般是.a文件)和動(dòng)態(tài)庫(kù)(dynamic lib矛辕,也叫共享庫(kù),在linux系統(tǒng)一般是.so文件)付魔。二者的不同點(diǎn)在于被載入的時(shí)間不同:

  • 靜態(tài)庫(kù).a在編譯的過(guò)程中會(huì)被編譯到可執(zhí)行文件聊品,也就是說(shuō)會(huì)增大可執(zhí)行文件的體積。
  • 動(dòng)態(tài)庫(kù)則是在執(zhí)行的過(guò)程中才會(huì)去讀取.so文件几苍,不用編譯進(jìn)可執(zhí)行程序翻屈,因此可執(zhí)行程序體積較小。缺點(diǎn)是拷貝代碼時(shí)如果沒(méi)有.so文件可能會(huì)造成無(wú)法執(zhí)行妻坝∩炜簦‘

2.靜態(tài)庫(kù)

靜態(tài)庫(kù)

程序在編譯階段會(huì)把靜態(tài)庫(kù)的內(nèi)容復(fù)制到目標(biāo)文件中惊窖,在鏈接階段將引用的靜態(tài)庫(kù)打包到可執(zhí)行文件中。因此稱為靜態(tài)鏈接赚抡。這里可以發(fā)現(xiàn)爬坑,靜態(tài)鏈接將靜態(tài)庫(kù)直接打包進(jìn)入可執(zhí)行文件纠屋,那么他的組織形式一定和.o文件類似涂臣。

實(shí)際上,一個(gè)靜態(tài)庫(kù)是一組目標(biāo)文件的集合(.o)售担,很多目標(biāo)文件被打包成一個(gè)文件赁遗,并且直接參與鏈接。

靜態(tài)庫(kù)有以下特點(diǎn):

  • 1.靜態(tài)庫(kù)對(duì)函數(shù)的鏈接是在編譯時(shí)完成的
  • 2.程序在運(yùn)行時(shí)不再需要靜態(tài)庫(kù)族铆,因?yàn)閷?duì)應(yīng)的程序段已經(jīng)被復(fù)制到原來(lái)的位置岩四,移植方便。
  • 3.可執(zhí)行文件占用空間較大哥攘,因?yàn)殪o態(tài)庫(kù)內(nèi)容被復(fù)制進(jìn)入了可執(zhí)行文件編譯結(jié)果剖煌。

創(chuàng)建靜態(tài)庫(kù)

  1. linux靜態(tài)庫(kù)的創(chuàng)建命名規(guī)則:lib[library_name].a,lib為前綴,中間是庫(kù)名逝淹,.a為擴(kuò)展名耕姊。
  2. 創(chuàng)建靜態(tài)庫(kù)
    現(xiàn)在有如下代碼,一定要把頭文件和函數(shù)體分開(kāi)聲明栅葡,否則使用靜態(tài)庫(kù)的時(shí)候沒(méi)有頭文件只能猜了哦茉兰。
**
* @file: unite_time.h
* @author: mattbaisteins@gmail.com
* @date: 2020-08-03
* @brif:
**/
#ifndef _UNITE_TIME_H
#define _UNITE_TIME_H
#include <ctime>
#include <sys/time.h>
#include <string>
#include <vector>
#include <cstdlib>
 
 
 #define BUFFER_SIZE 4096
  /*
   * get time yymmdd, eg. 190803
   * @param void
  * @return string now_time
   */
 std::string get_time();
 
  #endif // end _UNITE_TIME_H
 
   /**
    * @file: unite_time.cpp
    * @author: mattbaisteins@gmail.com
    * @date: 2020-08-03
    * @brif:
    **/
  
   #include "unite_time.h"
   #include <ctime>
  std::string get_time() {
      time_t raw_time;
      struct std::tm *time_info;
      char buffer[BUFFER_SIZE];
      std::time(&raw_time);
      time_info = std::localtime(&raw_time);
      std::strftime(buffer, sizeof(buffer) - 1, "%y%m%d", time_info);
      return std::string(buffer);
  }
 

1.首先把代碼先編譯成目標(biāo)文件.o(unite_time.o)

gcc -c unite_time.cpp

2 使用ar工具將目標(biāo)文件打包成靜態(tài)庫(kù).a文件(libunite_time.a)

ar -crv libunite_time.a unite_time.o

注:ar的用法如下

(1)ar是什么
  ar命令可以用來(lái)創(chuàng)建、修改庫(kù)欣簇,也可以從庫(kù)中提出單個(gè)模塊规脸。庫(kù)是一單獨(dú)的文件,里面包含了按照特定的結(jié)構(gòu)組織起來(lái)的其它的一些文件(稱做此庫(kù)文件的member)熊咽。原始文件的內(nèi)容莫鸭、模式、時(shí)間戳横殴、屬主黔龟、組等屬性都保留在庫(kù)文件中。
  ar命令格式:ar [-] {dmpqrtx} [abcfilNoPsSuvV] [membername] [count] archive files...
  例如我們可以用ar rv libtest.a hello.o hello1.o來(lái)生成一個(gè)庫(kù)滥玷,庫(kù)名字是test氏身,鏈接時(shí)可以用-ltest鏈接。該庫(kù)中存放了兩個(gè)模塊hello.o和hello1.o惑畴。選項(xiàng)前可以有‘-'字符蛋欣,也可以沒(méi)有。下面我們來(lái)看看命令的操作選項(xiàng)和任選項(xiàng)∪绱現(xiàn)在我們把{dmpqrtx}部分稱為操作選項(xiàng)陷虎,而[abcfilNoPsSuvV]部分稱為任選項(xiàng)到踏。
【注:ar可讓您集合許多文件,成為單一的備存文件尚猿。在備存文件中窝稿,所有成員文件皆保有原來(lái)的屬性與權(quán)限】

2)參數(shù)介紹 指令參數(shù)
-d  刪除庫(kù)文件中的成員文件。
-m  變更成員文件在庫(kù)文件中的次序凿掂。
-p  顯示庫(kù)文件中的成員文件內(nèi)容伴榔。
-q  將問(wèn)家附加在庫(kù)文件末端。
-r  將文件插入庫(kù)文件中庄萎。
-t  顯示庫(kù)文件中所包含的文件踪少。
-x  自庫(kù)文件中取出成員文件。
選項(xiàng)參數(shù)
a<成員文件>  將文件插入庫(kù)文件中指定的成員文件之后糠涛。
b <成員文件>  將文件插入庫(kù)文件中指定的成員文件之前援奢。
c  建立庫(kù)文件。
f  為避免過(guò)長(zhǎng)的文件名不兼容于其他系統(tǒng)的ar指令指令忍捡,因此可利用此參數(shù)集漾,截掉要放入庫(kù)文件中過(guò)長(zhǎng)的成員文件名稱。
i<成員文件>  將問(wèn)家插入庫(kù)文件中指定的成員文件之前砸脊。
o  保留庫(kù)文件中文件的日期具篇。
s  若庫(kù)文件中包含了對(duì)象模式,可利用此參數(shù)建立備存文件的符號(hào)表脓规。
S  不產(chǎn)生符號(hào)表栽连。
u  只將日期較新文件插入庫(kù)文件中。
v  程序執(zhí)行時(shí)顯示詳細(xì)的信息侨舆。
V  顯示版本信息秒紧。
ar用來(lái)管理一種文檔。這種文檔中可以包含多個(gè)其他任意類別的文件挨下。這些被包含的文件叫做這個(gè)文檔的成員熔恢。ar用來(lái)向這種文檔中添加、刪除臭笆、解出成員叙淌。成員的原有屬性(權(quán)限、屬主愁铺、日期等)不會(huì)丟失鹰霍。實(shí)際上通常只有在開(kāi)發(fā)中的目標(biāo)連接庫(kù)是這種格式的,所以盡管不是茵乱,我們基本可以認(rèn)為ar是用來(lái)操作這種目標(biāo)鏈接庫(kù)(.a文件)的茂洒。

(3)ar的常用用法
創(chuàng)建庫(kù)文件
我不知道怎么創(chuàng)建一個(gè)空的庫(kù)文件。好在這個(gè)功能好像不是很需要瓶竭。通常人們使用“ar cru liba.a a.o"這樣的命令來(lái)創(chuàng)建一個(gè)庫(kù)并把a(bǔ).o添加進(jìn)去督勺。"c"關(guān)鍵字告訴ar需要?jiǎng)?chuàng)建一個(gè)新庫(kù)文件渠羞,如果沒(méi)有指定這個(gè)標(biāo)志則ar會(huì)創(chuàng)建一個(gè)文件,同時(shí)會(huì)給出 一個(gè)提示信息智哀,"u"用來(lái)告訴ar如果a.o比庫(kù)中的同名成員要新次询,則用新的a.o替換原來(lái)的。但是我發(fā)現(xiàn)這個(gè)參數(shù)也是可有可無(wú)的瓷叫,可能是不同版本的ar 行為不一樣吧屯吊。實(shí)際上用"ar -r liba.a a.o"在freebsd5上面始終可以成功。
加入新成員
使用"ar -r liba.a b.o"即可以將b.o加入到liba.a中赞辩。默認(rèn)的加入方式為append雌芽,即加在庫(kù)的末尾授艰。"r"關(guān)鍵字可以有三個(gè)修飾符"a", "b"和"i"辨嗽。 "a"表示after,即將新成員加在指定成員之后淮腾。例如"ar -ra a.c liba.a b.c"表示將b.c加入liba.a并放在已有成員a.c之后糟需; "b"表示before,即將新成員加在指定成員之前谷朝。例如"ar -rb a.c liba.a b.c"洲押; "i"表示insert,跟"b"作用相同圆凰。
列出庫(kù)中已有成員
"ar -t liba.a"即可杈帐。如果加上"v"修飾符則會(huì)一并列出成員的日期等屬性。
刪除庫(kù)中成員
"ar -d liba.a a.c"表示從庫(kù)中刪除a.c成員专钉。如果庫(kù)中沒(méi)有這個(gè)成員ar也不會(huì)給出提示挑童。如果需要列出被刪除的成員或者成員不存在的信息,就加上"v"修飾符跃须。
從庫(kù)中解出成員
"ar -x liba.a b.c"
調(diào)整庫(kù)中成員的順序
使用"m"關(guān)鍵字站叼。與"r"關(guān)鍵字一樣,它也有3個(gè)修飾符"a","b", "i"菇民。如果要將b.c移動(dòng)到a.c之前尽楔,則使用"ar -mb a.c liba.a b.c"

使用用靜態(tài)庫(kù)


    1 #include <iostream>
    2 #include <string>
    3 #include "unite_time.h"
    4
    5 int main() {
    6     std::cout << "test static lib" << std::endl;
    7     std::cout << get_time() << std::endl;
    8     return 0;
    9
   10 }

Linux下使用靜態(tài)庫(kù),只需要在編譯的時(shí)候第练,指定靜態(tài)庫(kù)的搜索路徑(-L選項(xiàng))阔馋、指定靜態(tài)庫(kù)名(不需要lib前綴和.a后綴,-l選項(xiàng))娇掏。

g++ test.cpp -L./ -lunite_time -o test

就可以生成可執(zhí)行文件test啦呕寝,,我們執(zhí)行可執(zhí)行文件test驹碍,可以看到test 二進(jìn)制包大小是24k壁涎,成功生成了libunite_time.a


靜態(tài)庫(kù)

3.動(dòng)態(tài)庫(kù)

動(dòng)態(tài)庫(kù)

動(dòng)態(tài)庫(kù)凡恍,動(dòng)態(tài)庫(kù)是在程序運(yùn)行時(shí)被載入引用。 只在程序中做一個(gè)標(biāo)記怔球,當(dāng)用到被標(biāo)記的庫(kù)中的函數(shù)時(shí)嚼酝,程序會(huì)順著做的標(biāo)記找到庫(kù),然后調(diào)用需要的函數(shù)竟坛,并不會(huì)像靜態(tài)庫(kù)一樣將庫(kù)中的所有內(nèi)容都復(fù)制包含進(jìn)來(lái)闽巩。

為什么有了靜態(tài)庫(kù)還要設(shè)計(jì)動(dòng)態(tài)庫(kù)?

  • 首先是空間浪費(fèi)是靜態(tài)庫(kù)的一個(gè)問(wèn)題担汤。我們可以這樣想假如某一個(gè)人靜態(tài)庫(kù)占用1M內(nèi)存涎跨,此時(shí)有2000個(gè)這樣的程序需要用到這個(gè)庫(kù),那么此時(shí)崭歧,每個(gè)程序都需要將這個(gè)靜態(tài)庫(kù)中的內(nèi)容拷貝一份到自己里面隅很,這樣內(nèi)存中就會(huì)產(chǎn)生多分庫(kù)函數(shù),并且這些會(huì)占用將近2GB的空間率碾。

  • 另外一個(gè)問(wèn)題是由于靜態(tài)庫(kù)對(duì)程序的更新叔营、部署和發(fā)布帶來(lái)的麻煩。假如某一個(gè)靜態(tài)庫(kù)更新了所宰,所有使用它的應(yīng)用程序都需要重新編譯绒尊、發(fā)布給用戶(對(duì)于玩家來(lái)說(shuō),只是一個(gè)小小的改動(dòng)仔粥,但是卻會(huì)導(dǎo)致整個(gè)程序重新下載婴谱,全量更新)

  • 因此我們需要引入動(dòng)態(tài)庫(kù),由于動(dòng)態(tài)庫(kù)是程序運(yùn)行時(shí)被載入的躯泰,不同的程序如果調(diào)用相同的庫(kù)谭羔,在內(nèi)存中里只需要有一份該庫(kù)的實(shí)例,避免了空間的浪費(fèi)斟冕,同時(shí)也解決了靜態(tài)庫(kù)對(duì)程序的更新口糕、部署和發(fā)布帶來(lái)的麻煩,用戶只需要更新動(dòng)態(tài)庫(kù)即可磕蛇,增量更新景描。

動(dòng)態(tài)庫(kù)特點(diǎn)總結(jié):

   (1)動(dòng)態(tài)庫(kù)把對(duì)一些庫(kù)函數(shù)的鏈接載入推遲到程序運(yùn)行的時(shí)期⌒闫玻 

   (2)可以實(shí)現(xiàn)進(jìn)程之間的資源共享超棺。(因此動(dòng)態(tài)庫(kù)也稱為共享庫(kù))

   (3)將一些程序升級(jí)變得簡(jiǎn)單。

   (4)甚至可以真正做到鏈接載入完全由程序員在程序代碼中控制(顯式調(diào)用)呵燕。

## 創(chuàng)建動(dòng)態(tài)庫(kù)
1.linux動(dòng)態(tài)庫(kù)的命名規(guī)則
  動(dòng)態(tài)鏈接庫(kù)的名字形式為 libxxx.so棠绘,前綴是 lib,后綴名為“.so”;針對(duì)于實(shí)際庫(kù)文件氧苍,每個(gè)共享庫(kù)都有個(gè)特殊的名字“so name”夜矗。在程序啟動(dòng)后,程序通過(guò)這個(gè)名字來(lái)告訴動(dòng)態(tài)加載器让虐,該載入哪個(gè)共享庫(kù)紊撕;在文件系統(tǒng)中,soname僅是一個(gè)鏈接到實(shí)際動(dòng)態(tài)庫(kù)的鏈接赡突。對(duì)于動(dòng)態(tài)庫(kù)而言对扶,每個(gè)庫(kù)實(shí)際上都有另一個(gè)名字給編譯器來(lái)用。它是一個(gè)指向?qū)嶋H庫(kù)鏡像文件的鏈接文件(lib+soname+.so)惭缰。

2.創(chuàng)建動(dòng)態(tài)庫(kù)(.so)
同樣是上面的代碼

第一步:生成位置無(wú)關(guān)的目標(biāo)文件.o(unite_time.o)浪南,此時(shí)要加編譯器選項(xiàng)-fpic

g++ -fPIC -c unite_time.cpp //-fPIC 創(chuàng)建與地址無(wú)關(guān)的編譯程序(pic,position independent code)漱受,是為了能夠在多個(gè)應(yīng)用程序間共享络凿。

第二步:生成動(dòng)態(tài)庫(kù),此時(shí)要加鏈接器選項(xiàng)-shared

g++ -shared -o libunite_time.so unite_time.o

也可以將上面兩步合為一步

 g++ -fPIC -shared -o libunite_time.so unite_time.cpp

使用動(dòng)態(tài)庫(kù)

g++ test.cpp -L./ -lunite_time -o test
動(dòng)態(tài)庫(kù)

Linux系統(tǒng)在同一目錄下有可能找不到動(dòng)態(tài)庫(kù)位置拜效,那么在執(zhí)行程序時(shí)如何定位動(dòng)態(tài)庫(kù)的位置呢喷众?

(1) 當(dāng)系統(tǒng)加載可執(zhí)行代碼時(shí)候各谚,能夠知道其所依賴的庫(kù)的名字紧憾,但是還需要知道絕對(duì)路徑。此時(shí)就需要系統(tǒng)動(dòng)態(tài)載入器(dynamic linker/loader)昌渤。
(2)對(duì)于elf格式的可執(zhí)行程序赴穗,是由ld-linux.so*來(lái)完成的,它先后搜索elf文件的 DT_RPATH段—環(huán)境變LD_LIBRARY_PATH—/etc/ld.so.cache文件列表—/lib/,/usr/lib 目錄找到庫(kù)文件后將其載入內(nèi)存膀息。

如何讓系統(tǒng)能夠找到它般眉?

(1)如果安裝在/lib或者/usr/lib下,那么ld默認(rèn)能夠找到潜支,無(wú)需其它操作甸赃。
(2)如果安裝在其它目錄,需要將其添加到/etc/ld.so.cache文件中冗酿,步驟如下:

第一步:編輯/etc/ld.so.conf文件埠对,加入庫(kù)文件所在目錄的路徑
第二步:運(yùn)行l(wèi)dconfig ,該命令會(huì)重建/etc/ld.so.cache文件

4使用動(dòng)態(tài)庫(kù)運(yùn)行時(shí)加載的特性做熱更新

根據(jù)動(dòng)態(tài)庫(kù)運(yùn)行時(shí)加載的特性裁替,我們可以在不重新編譯可執(zhí)行文件的情況下项玛,對(duì)動(dòng)態(tài)庫(kù)進(jìn)行熱更新,使得test執(zhí)行過(guò)程中執(zhí)行熱熱加載
我們修改一下庫(kù)函數(shù)的內(nèi)容

 /**
    * @file: unite_time.cpp
    * @author: mattbaisteins@gmail.com
    * @date: 2020-08-03
    * @brif:
    **/
  
   #include "unite_time.h"
   #include <ctime>
  std::string get_time() {
      return "hello world";
  }
 

重新生成動(dòng)態(tài)庫(kù)弱判,不重新編譯可執(zhí)行文件襟沮,可以發(fā)現(xiàn)結(jié)果已經(jīng)變成了新的動(dòng)態(tài)庫(kù)內(nèi)容


動(dòng)態(tài)庫(kù)熱更新

熱加載

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子开伏,更是在濱河造成了極大的恐慌膀跌,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件固灵,死亡現(xiàn)場(chǎng)離奇詭異淹父,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)怎虫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門暑认,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人大审,你說(shuō)我怎么就攤上這事蘸际。” “怎么了徒扶?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵粮彤,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我姜骡,道長(zhǎng)导坟,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任圈澈,我火速辦了婚禮惫周,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘康栈。我一直安慰自己递递,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布啥么。 她就那樣靜靜地躺著登舞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪悬荣。 梳的紋絲不亂的頭發(fā)上菠秒,一...
    開(kāi)封第一講書(shū)人閱讀 51,624評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音氯迂,去河邊找鬼践叠。 笑死,一個(gè)胖子當(dāng)著我的面吹牛囚戚,可吹牛的內(nèi)容都是我干的酵熙。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼驰坊,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼匾二!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤察藐,失蹤者是張志新(化名)和其女友劉穎皮璧,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體分飞,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡悴务,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了譬猫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片讯檐。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖染服,靈堂內(nèi)的尸體忽然破棺而出别洪,到底是詐尸還是另有隱情,我是刑警寧澤柳刮,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布挖垛,位于F島的核電站,受9級(jí)特大地震影響秉颗,放射性物質(zhì)發(fā)生泄漏痢毒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一蚕甥、第九天 我趴在偏房一處隱蔽的房頂上張望哪替。 院中可真熱鬧,春花似錦梢灭、人聲如沸夷家。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至摸袁,卻和暖如春钥顽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背靠汁。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工蜂大, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蝶怔。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓奶浦,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親踢星。 傳聞我的和親對(duì)象是個(gè)殘疾皇子澳叉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355