精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

C語(yǔ)言的高級(jí)用法

開發(fā) 后端
在C語(yǔ)言中,定義了4個(gè)內(nèi)存區(qū)間:代碼區(qū);全局變量和靜態(tài)變量區(qū);局部變量區(qū)即棧區(qū);動(dòng)態(tài)存儲(chǔ)區(qū),即堆區(qū);具體如下。

一、內(nèi)存管理

我們需要知道——變量,其實(shí)是內(nèi)存地址的一個(gè)抽像名字罷了。在靜態(tài)編譯的程序中,所有的變量名都會(huì)在編譯時(shí)被轉(zhuǎn)成內(nèi)存地址。機(jī)器是不知道我們?nèi)〉拿值模恢赖刂贰? 

內(nèi)存的使用時(shí)程序設(shè)計(jì)中需要考慮的重要因素之一,這不僅由于系統(tǒng)內(nèi)存是有限的(尤其在嵌入式系統(tǒng)中),而且內(nèi)存分配也會(huì)直接影響到程序的效率。因此,我們要對(duì)C語(yǔ)言中的內(nèi)存管理,有個(gè)系統(tǒng)的了解。  

在C語(yǔ)言中,定義了4個(gè)內(nèi)存區(qū)間:代碼區(qū);全局變量和靜態(tài)變量區(qū);局部變量區(qū)即棧區(qū);動(dòng)態(tài)存儲(chǔ)區(qū),即堆區(qū);具體如下:  

1>棧區(qū)(stack)— 由編譯器自動(dòng)分配釋放 ,存放函數(shù)的參數(shù)值,局部變量的值等。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧。

2>堆區(qū)(heap) — 一般由程序員分配釋放, 若程序員不釋放,程序結(jié)束時(shí)可能由OS回收 。注意它與數(shù)據(jù)結(jié)構(gòu)中的堆是兩回事,分配方式倒是類似于鏈表。  

3>全局區(qū)(靜態(tài)區(qū))(static)—全局變量和靜態(tài)變量的存儲(chǔ)是放在一塊的,初始化的全局變量和靜態(tài)變量在一塊區(qū)域, 未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的 另一塊區(qū)域。- 程序結(jié)束后由系統(tǒng)釋放。  

4>常量區(qū) —常量字符串就是放在這里的。程序結(jié)束后由系統(tǒng)釋放。  

5>程序代碼區(qū)—存放函數(shù)體的二進(jìn)制代碼。  

我們來看張圖:  

圖1

首先我們要知道,源代碼編譯成程序,程序是放在硬盤上的,而非內(nèi)存里!只有執(zhí)行時(shí)才會(huì)被調(diào)用到內(nèi)存中!我們來看看程序結(jié)構(gòu),ELF是是Linux的主要可執(zhí)行文件格式。ELF文件由4部分組成,分別是ELF頭(ELF header)、程序頭表(Program header table)、節(jié)(Section)和節(jié)頭表(Section header table)。具體如下:  

1>Program header描述的是一個(gè)段在文件中的位置、大小以及它被放進(jìn)內(nèi)存后所在的位置和大小。即要加載的信息;  

2>Sections保存著object 文件的信息,從連接角度看:包括指令,數(shù)據(jù),符號(hào)表,重定位信息等等。在圖中,我們可以看到Sections中包括:  

  • text 文本結(jié) 存放指令;
  • rodata 數(shù)據(jù)結(jié) readonly;
  • data 數(shù)據(jù)結(jié) 可讀可寫;

3>Section頭表(section header table)包含了描述文件sections的信息。每個(gè)section在這個(gè)表中有一個(gè)入口;每個(gè)入口給出了該section的名字,大小,等等信息。相當(dāng)于 索引!  

而程序被加載到內(nèi)存里面,又是如何分布的呢?我們看看上圖中:

正文和初始化的數(shù)據(jù)和未初始化的數(shù)據(jù)就是我們所說的數(shù)據(jù)段,正文即代碼段;  

2>正文段上面是常量區(qū),常量區(qū)上面是全局變量和靜態(tài)變量區(qū),二者占據(jù)的就是初始化的數(shù)據(jù)和未初始化的數(shù)據(jù)那部分;  

3>再上面就是堆,動(dòng)態(tài)存儲(chǔ)區(qū),這里是上增長(zhǎng);  

4>堆上面是棧,存放的是局部變量,就是局部變量所在代碼塊執(zhí)行完畢后,這塊內(nèi)存會(huì)被釋放,這里棧區(qū)是下增長(zhǎng);  

5>命令行參數(shù)就是001之類的,環(huán)境變量什么的前面的文章已經(jīng)講過,有興趣的可以去看看。  

我們知道,內(nèi)存分為動(dòng)態(tài)內(nèi)存和靜態(tài)內(nèi)存,我們先講靜態(tài)內(nèi)存。

靜態(tài)內(nèi)存

存儲(chǔ)模型決定了一個(gè)變量的內(nèi)存分配方式和訪問特性,在C語(yǔ)言中主要有三個(gè)維度來決定:存儲(chǔ)時(shí)期 、作用域 、鏈接。  

1、存儲(chǔ)時(shí)期  

存儲(chǔ)時(shí)期:變量在內(nèi)存中的保留時(shí)間(生命周期)  

存儲(chǔ)時(shí)期分為兩種情況,關(guān)鍵是看變量在程序執(zhí)行過程中會(huì)不會(huì)被系統(tǒng)自動(dòng)回收掉。  

1) 靜態(tài)存儲(chǔ)時(shí)期 Static  

在程序執(zhí)行過程中一旦分配就不會(huì)被自動(dòng)回收。  

通常來說,任何不在函數(shù)級(jí)別代碼塊內(nèi)定義的變量。  

無論是否在代碼塊內(nèi),只要采用static關(guān)鍵字修飾的變量。  

2) 自動(dòng)存儲(chǔ)時(shí)期 Automatic  

除了靜態(tài)存儲(chǔ)以外的變量都是自動(dòng)存儲(chǔ)時(shí)期的,或者說只要是在代碼塊內(nèi)定義的非static的變量,系統(tǒng)會(huì)肚臍自動(dòng)非配和釋放內(nèi)存;  

2、作用域  

作用域:一個(gè)變量在定義該變量的自身文件中的可見性(訪問或者引用)  

在C語(yǔ)言中,一共有3中作用域:  

1) 代碼塊作用域  

在代碼塊中定義的變量都具有該代碼的作用域。從這個(gè)變量定義地方開始,到這個(gè)代碼塊結(jié)束,該變量是可見的;  

2) 函數(shù)原型作用域  

出現(xiàn)在函數(shù)原型中的變量,都具有函數(shù)原型作用域,函數(shù)原型作用域從變量定義處一直到原型聲明的末尾。  

3) 文件作用域  

一個(gè)在所有函數(shù)之外定義的變量具有文件作用域,具有文件作用域的變量從它的定義處到包含該定義的文件結(jié)尾處都是可見的;  

3、鏈接  

鏈接:一個(gè)變量在組成程序的所有文件中的可見性(訪問或者引用);  

C語(yǔ)言中一共有三種不同的鏈接:  

1) 外部鏈接  

如果一個(gè)變量在組成一個(gè)程序的所有文件中的任何位置都可以被訪問,則稱該變量支持外部鏈接;  

2) 內(nèi)部鏈接  

如果一個(gè)變量只可以在定義其自身的文件中的任何位置被訪問,則稱該變量支持內(nèi)部鏈接。  

3) 空鏈接  

如果一個(gè)變量只是被定義其自身的當(dāng)前代碼塊所私有,不能被程序的其他部分所訪問,則成該變量支持空鏈接  

我們來看一個(gè)代碼示例:

#include <stdio.h>  
int a = 0;// 全局初始化區(qū)
char *p1; //全局未初始化區(qū)
int main()
{
int b; //b在棧區(qū)
char s[] = "abc"; //棧
char *p2; //p2在棧區(qū)
char *p3 = "123456"; //123456\0在常量區(qū),p3在棧上。
static int c =0//全局(靜態(tài))初始化區(qū)
p1 = (char *)malloc(10);
p2 = (char *)malloc(20); //分配得來得10和20字節(jié)的區(qū)域就在堆區(qū)。
strcpy(p1, "123456"); //123456\0放在常量區(qū),編譯器可能會(huì)將它與p3所指向的"123456"優(yōu)化成一個(gè)地方。
}

1.2動(dòng)態(tài)內(nèi)存

當(dāng)程序運(yùn)行到需要一個(gè)動(dòng)態(tài)分配的變量時(shí),必須向系統(tǒng)申請(qǐng)取得堆中的一塊所需大小的存儲(chǔ)空間,用于存儲(chǔ)該變量。當(dāng)不在使用該變量時(shí),也就是它的生命結(jié)束時(shí),要顯示釋放它所占用的存儲(chǔ)空間,這樣系統(tǒng)就能對(duì)該空間 進(jìn)行再次分配,做到重復(fù)使用有線的資源。下面介紹動(dòng)態(tài)內(nèi)存申請(qǐng)和釋放的函數(shù)。

1.2.1 malloc 函數(shù)

malloc函數(shù)原型:

size是需要?jiǎng)討B(tài)申請(qǐng)的內(nèi)存的字節(jié)數(shù)。若申請(qǐng)成功,函數(shù)返回申請(qǐng)到的內(nèi)存的起始地址,若申請(qǐng)失敗,返回NULL。我們看下面這個(gè)例子:

使用該函數(shù)時(shí),有下面幾點(diǎn)要注意:  

1)只關(guān)心申請(qǐng)內(nèi)存的大小;  

2)申請(qǐng)的是一塊連續(xù)的內(nèi)存。記得一定要寫出錯(cuò)判斷;  

3)顯示初始化。即我們不知這塊內(nèi)存中有什么東西,要對(duì)其清零;

1.2.2 free函數(shù)

在堆上分配的額內(nèi)存,需要用free函數(shù)顯示釋放,函數(shù)原型如下:

使用free(),也有下面幾點(diǎn)要注意:  

1)必須提供內(nèi)存的起始地址;  

調(diào)用該函數(shù)時(shí),必須提供內(nèi)存的起始地址,不能夠提供部分地址,釋放內(nèi)存中的一部分是不允許的。  

2)malloc和free配對(duì)使用;  

編譯器不負(fù)責(zé)動(dòng)態(tài)內(nèi)存的釋放,需要程序員顯示釋放。因此,malloc與free是配對(duì)使用的,避免內(nèi)存泄漏。

p = NULL是必須的,因?yàn)殡m然這塊內(nèi)存被釋放了,但是p仍指向這塊內(nèi)存,避免下次對(duì)p的誤操作;  

3)不允許重復(fù)釋放  

因?yàn)檫@塊內(nèi)存被釋放后,可能已另分配,這塊區(qū)域被別人占用,如果再次釋放,會(huì)造成數(shù)據(jù)丟失;

1.2.3 其它相關(guān)函數(shù)

calloc函數(shù)分配內(nèi)存需要考慮存儲(chǔ)位置的類型。  

realloc函數(shù)可以調(diào)整一段動(dòng)態(tài)分配內(nèi)存的大小

1.3堆和棧比較

1)申請(qǐng)方式  

stack: 由系統(tǒng)自動(dòng)分配。例如,聲明在函數(shù)中一個(gè)局部變量 int b; 系統(tǒng)自動(dòng)在棧中為b開辟空間  

heap: 需要程序員自己申請(qǐng),并指明大小,在c中malloc函數(shù) ,如p1 = (char *)malloc(10);  

2)申請(qǐng)后系統(tǒng)的響應(yīng)  

棧:只要棧的剩余空間大于所申請(qǐng)空間,系統(tǒng)將為程序提供內(nèi)存,否則將報(bào)異常提示棧溢出。  

堆:首先應(yīng)該知道操作系統(tǒng)有一個(gè)記錄空閑內(nèi)存地址的鏈表,當(dāng)系統(tǒng)收到程序的申請(qǐng)時(shí),會(huì)遍歷該鏈表,尋找第一個(gè)空間大于所申請(qǐng)空間的堆結(jié)點(diǎn),然后將該結(jié)點(diǎn)從空閑結(jié)點(diǎn)鏈表中刪除,并將該結(jié)點(diǎn)的空間分配給程序,另外,對(duì)于大多數(shù)系統(tǒng),會(huì)在這塊內(nèi)存空間中的首地址處記錄本次分配的大小,這樣,代碼中的delete語(yǔ)句才能正確的釋放本內(nèi)存空間。另外,由于找到的堆結(jié)點(diǎn)的大小不一定正好等于申請(qǐng)的大小,系統(tǒng)會(huì)自動(dòng)的將多余的那部分重新放入空閑鏈表中。  

3)申請(qǐng)大小的限制  

棧:棧是向低地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是一塊連續(xù)的內(nèi)存的區(qū)域。這句話的意思是棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預(yù)先規(guī)定好的,棧的大小是2M(也有的說是1M,總之是一個(gè)編譯時(shí)就確定的常數(shù)),如果申請(qǐng)的空間超過棧的剩余空間時(shí),將提示overflow。因此,能從棧獲得的空間較小。  

堆:堆是向高地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是不連續(xù)的內(nèi)存區(qū)域。這是由于系統(tǒng)是用鏈表來存儲(chǔ)的空閑內(nèi)存地址的,自然是不連續(xù)的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限于計(jì)算機(jī)系統(tǒng)中有效的虛擬內(nèi)存。由此可見,堆獲得的空間比較靈活,也比較大。  

4)申請(qǐng)效率的比較  

棧由系統(tǒng)自動(dòng)分配,速度較快。但程序員是無法控制的。  

堆是由new分配的內(nèi)存,一般速度比較慢,而且容易產(chǎn)生內(nèi)存碎片,不過用起來最方便。  

5)堆和棧中的存儲(chǔ)內(nèi)容  

棧:在函數(shù)調(diào)用時(shí),第一個(gè)進(jìn)棧的是主函數(shù)中后的下一條指令(函數(shù)調(diào)用語(yǔ)句的下一條可執(zhí)行語(yǔ)句)的地址,然后是函數(shù)的各個(gè)參數(shù),在大多數(shù)的C編譯器中,參數(shù)是由右往左入棧的,然后是函數(shù)中的局部變量。注意靜態(tài)變量是不入棧的。當(dāng)本次函數(shù)調(diào)用結(jié)束后,局部變量先出棧,然后是參數(shù),最后棧頂指針指向最開始存的地址,也就是主函數(shù)中的下一條指令,程序由該點(diǎn)繼續(xù)運(yùn)行。  

堆:一般是在堆的頭部用一個(gè)字節(jié)存放堆的大小。堆中的具體內(nèi)容由程序員安排。  

6)存取效率的比較

char s1[] = "aaaaaaaaaaaaaaa";

char *s2 = "bbbbbbbbbbbbbbbbb";  

aaaaaaaaaaa是在運(yùn)行時(shí)刻賦值的;  

而bbbbbbbbbbb是在編譯時(shí)就確定的;  

但是,在以后的存取中,在棧上的數(shù)組比指針?biāo)赶虻淖址?例如堆)快。  

比如:

對(duì)應(yīng)的匯編代碼

第一種在讀取時(shí)直接就把字符串中的元素讀到寄存器cl中,而第二種則要先把指針值讀到edx中,再根據(jù)edx讀取字符,顯然慢了。  

7)最后總結(jié)  

堆和棧的區(qū)別可以用如下的比喻來看出:  

棧就像我們?nèi)ワ堭^里吃飯,只管點(diǎn)菜(發(fā)出申請(qǐng))、付錢、和吃(使用),吃飽了就走,不必理會(huì)切菜、洗菜等準(zhǔn)備工作和洗碗、刷鍋等掃尾工作,他的好處是快捷,但是自由度小。  

堆就象是自己動(dòng)手做喜歡吃的菜肴,比較麻煩,但是比較符合自己的口味,而且自由度大。  

二、內(nèi)容對(duì)齊

2.1 #pragma pack(n) 對(duì)齊用法詳解

1).什么是對(duì)齊,以及為什么要對(duì)齊  

現(xiàn)代計(jì)算機(jī)中內(nèi)存空間都是按照byte劃分的,從理論上講似乎對(duì)任何類型的變量的訪問可以從任何地址開始,但實(shí)際情況是在訪問特定變量的時(shí)候經(jīng)常在特定的內(nèi)存地址訪問,這就需要各類型數(shù)據(jù)按照一定的規(guī)則在空間上排列,而不是順序的一個(gè)接一個(gè)的排放,這就是對(duì)齊。  

對(duì)齊的作用和原因:各個(gè)硬件平臺(tái)對(duì)存儲(chǔ)空間的處理上有很大的不同。一些平臺(tái)對(duì)某些特定類型的數(shù)據(jù)只能從某些特定地址開始存取。其他平臺(tái)可能沒有這種情況, 但是最常見的是如果不按照適合其平臺(tái)要求對(duì)數(shù)據(jù)存放進(jìn)行對(duì)齊,會(huì)在存取效率上帶來?yè)p失。比如有些平臺(tái)每次讀都是從偶地址開始,如果一個(gè)int型(假設(shè)為 32位系統(tǒng))如果存放在偶地址開始的地方,那么一個(gè)讀周期就可以讀出,而如果存放在奇地址開始的地方,就可能會(huì)需要2個(gè)讀周期,并對(duì)兩次讀出的結(jié)果的高低字節(jié)進(jìn)行拼湊才能得到該int數(shù)據(jù)。顯然在讀取效率上下降很多。這也是空間和時(shí)間的博弈。  

2).對(duì)齊的實(shí)現(xiàn)  

通常,我們寫程序的時(shí)候,不需要考慮對(duì)齊問題。編譯器會(huì)替我們選擇時(shí)候目標(biāo)平臺(tái)的對(duì)齊策略。當(dāng)然,我們也可以通知給編譯器傳遞預(yù)編譯指令而改變對(duì)指定數(shù)據(jù)的對(duì)齊方法。但是,正因?yàn)槲覀円话悴恍枰P(guān)心這個(gè)問題,所以因?yàn)榫庉嬈鲗?duì)數(shù)據(jù)存放做了對(duì)齊,而我們不了解的話,常常會(huì)對(duì)一些問題感到迷惑。最常見的就是struct數(shù)據(jù)結(jié)構(gòu)的sizeof結(jié)果,出乎意料。為此,我們需要對(duì)對(duì)齊算法所了解。  

作用:  

指定結(jié)構(gòu)體、聯(lián)合以及類成員的packing alignment;  

語(yǔ)法:

#pragma pack( [show] | [push | pop] [, identifier], n )

說明:  

1>pack提供數(shù)據(jù)聲明級(jí)別的控制,對(duì)定義不起作用;  

2>調(diào)用pack時(shí)不指定參數(shù),n將被設(shè)成默認(rèn)值;  

3>一旦改變數(shù)據(jù)類型的alignment,直接效果就是占用memory的減少,但是performance會(huì)下降;

3).語(yǔ)法具體分析  

1>show:可選參數(shù);顯示當(dāng)前packing aligment的字節(jié)數(shù),以warning message的形式被顯示;  

2>push:可選參數(shù);將當(dāng)前指定的packing alignment數(shù)值進(jìn)行壓棧操作,這里的棧是the internal compiler stack,同時(shí)設(shè)置當(dāng)前的packing alignment為n;如果n沒有指定,則將當(dāng)前的packing alignment數(shù)值壓棧;  

3>pop:可選參數(shù);從internal compiler stack中刪除最頂端的record;如果沒有指定n,則當(dāng)前棧頂record即為新的packing alignment數(shù)值;如果指定了n,則n將成為新的packing aligment數(shù)值;如果指定了identifier,則internal compiler stack中的record都將被pop直到identifier被找到,然后pop出identitier,同時(shí)設(shè)置packing alignment數(shù)值為當(dāng)前棧頂?shù)膔ecord;如果指定的identifier并不存在于internal compiler stack,則pop操作被忽略;  

4>identifier:可選參數(shù);當(dāng)同push一起使用時(shí),賦予當(dāng)前被壓入棧中的record一個(gè)名稱;當(dāng)同pop一起使用時(shí),從internal compiler stack中pop出所有的record直到identifier被pop出,如果identifier沒有被找到,則忽略pop操作;  

5>n:可選參數(shù);指定packing的數(shù)值,以字節(jié)為單位;缺省數(shù)值是8,合法的數(shù)值分別是1、2、4、8、16。  

4).重要規(guī)則  

1>復(fù)雜類型中各個(gè)成員按照它們被聲明的順序在內(nèi)存中順序存儲(chǔ),第一個(gè)成員的地址和整個(gè)類型的地址相同;  

2>每個(gè)成員分別對(duì)齊,即每個(gè)成員按自己的方式對(duì)齊,并最小化長(zhǎng)度;規(guī)則就是每個(gè)成員按其類型的對(duì)齊參數(shù)(通常是這個(gè)類型的大小)和指定對(duì)齊參數(shù)中較小的一個(gè)對(duì)齊;  

3>結(jié)構(gòu)、聯(lián)合或者類的數(shù)據(jù)成員,第一個(gè)放在偏移為0的地方;以后每個(gè)數(shù)據(jù)成員的對(duì)齊,按照#pragma pack指定的數(shù)值和這個(gè)數(shù)據(jù)成員自身長(zhǎng)度兩個(gè)中比較小的那個(gè)進(jìn)行;也就是說,當(dāng)#pragma pack指定的值等于或者超過所有數(shù)據(jù)成員長(zhǎng)度的時(shí)候,這個(gè)指定值的大小將不產(chǎn)生任何效果;  

4>復(fù)雜類型(如結(jié)構(gòu))整體的對(duì)齊<注意是“整體”>是按照結(jié)構(gòu)體中長(zhǎng)度最大的數(shù)據(jù)成員和#pragma pack指定值之間較小的那個(gè)值進(jìn)行;這樣在成員是復(fù)雜類型時(shí),可以最小化長(zhǎng)度;  

5>結(jié)構(gòu)整體長(zhǎng)度的計(jì)算必須取所用過的所有對(duì)齊參數(shù)的整數(shù)倍,不夠補(bǔ)空字節(jié);也就是取所用過的所有對(duì)齊參數(shù)中最大的那個(gè)值的整數(shù)倍,因?yàn)閷?duì)齊參數(shù)都是2的n次方;這樣在處理數(shù)組時(shí)可以保證每一項(xiàng)都邊界對(duì)齊;  

5).對(duì)齊的算法  

由于各個(gè)平臺(tái)和編譯器的不同,現(xiàn)以本人使用的gcc version 3.2.2編譯器(32位x86平臺(tái))為例子,來討論編譯器對(duì)struct數(shù)據(jù)結(jié)構(gòu)中的各成員如何進(jìn)行對(duì)齊的。  

在相同的對(duì)齊方式下,結(jié)構(gòu)體內(nèi)部數(shù)據(jù)定義的順序不同,結(jié)構(gòu)體整體占據(jù)內(nèi)存空間也不同,如下:  

設(shè)結(jié)構(gòu)體如下定義:

結(jié)構(gòu)體A中包含了4字節(jié)長(zhǎng)度的int一個(gè),1字節(jié)長(zhǎng)度的char一個(gè)和2字節(jié)長(zhǎng)度的short型數(shù)據(jù)一個(gè)。所以A用到的空間應(yīng)該是7字節(jié)。但是因?yàn)榫幾g器要對(duì)數(shù)據(jù)成員在空間上進(jìn)行對(duì)齊。所以使用sizeof(strcut A)值為8。  

現(xiàn)在把該結(jié)構(gòu)體調(diào)整成員變量的順序。

這時(shí)候同樣是總共7個(gè)字節(jié)的變量,但是sizeof(struct B)的值卻是12。  

下面我們使用預(yù)編譯指令#progma pack (value)來告訴編譯器,使用我們指定的對(duì)齊值來取代缺省的。

sizeof(struct C)值是8。  

修改對(duì)齊值為1:

sizeof(struct D)值為7。

對(duì)于char型數(shù)據(jù),其自身對(duì)齊值為1,對(duì)于short型為2,對(duì)于int,float,double類型,其自身對(duì)齊值為4,單位字節(jié)。  

6).四個(gè)概念值  

1>數(shù)據(jù)類型自身的對(duì)齊值:就是上面交代的基本數(shù)據(jù)類型的自身對(duì)齊值。

2>指定對(duì)齊值:#progma pack (value)時(shí)的指定對(duì)齊值value。  

3>結(jié)構(gòu)體或者類的自身對(duì)齊值:其數(shù)據(jù)成員中自身對(duì)齊值最大的那個(gè)值。  

4>數(shù)據(jù)成員、結(jié)構(gòu)體和類的有效對(duì)齊值:自身對(duì)齊值和指定對(duì)齊值中小的那個(gè)值。有了這些值,我們就可以很方便的來討論具體數(shù)據(jù)結(jié)構(gòu)的成員和其自身的對(duì)齊方式。有效對(duì)齊值N是最終用來決定數(shù)據(jù)存放地址方式的值,最重要。有效對(duì)齊N,就是表示“對(duì)齊在N上”,也就是說該數(shù)據(jù)的”存放起始地址%N=0”. 而數(shù)據(jù)結(jié)構(gòu)中的數(shù)據(jù)變量都是按定義的先后順序來排放的。第一個(gè)數(shù)據(jù)變量的起始地址就是數(shù)據(jù)結(jié)構(gòu)的起始地址。結(jié)構(gòu)體的成員變量要對(duì)齊排放,結(jié)構(gòu)體本身也要根 據(jù)自身的有效對(duì)齊值圓整(就是結(jié)構(gòu)體成員變量占用總長(zhǎng)度需要是對(duì)結(jié)構(gòu)體有效對(duì)齊值的整數(shù)倍,結(jié)合下面例子理解)。這樣就不能理解上面的幾個(gè)例子的值了。  

例子分析:  

分析例子B;

假設(shè)B從地址空間0x0000開始排放。該例子中沒有定義指定對(duì)齊值,在筆者環(huán)境下,該值默認(rèn)為4。  

第一個(gè)成員變量b的自身對(duì)齊值是1,比指定或者默認(rèn)指定對(duì)齊值4小,所以其有效對(duì)齊值為1,所以其存放地址0x0000符合0x0000%1=0.  

第二個(gè)成員變量a,其自身對(duì)齊值為4,所以有效對(duì)齊值也為4,所以只能存放在起始地址為0x0004到0x0007這四個(gè)連續(xù)的字節(jié)空間中,符合0x0004%4=0, 且緊靠第一個(gè)變量。  

第三個(gè)變量c,自身對(duì)齊值為2,所以有效對(duì)齊值也是2,可以存放在0x0008到0x0009   這兩個(gè)字節(jié)空間中,符合0x0008%2=0。所以從0x0000到0x0009存放的都是B內(nèi)容。再看數(shù)據(jù)結(jié)構(gòu)B的自身對(duì)齊值為其變量中最大對(duì)齊值(這里是b)所以就是4,所以結(jié)構(gòu)體的有效對(duì)齊值也是4。根據(jù)結(jié)構(gòu)體圓整的要求,0x0009到0x0000=10字節(jié),(10+2)%4=0。所以0x0000A到0x000B也為結(jié)構(gòu)體B所占用。故B從0x0000到0x000B共有12個(gè)字節(jié),sizeof(struct B)=12;  

同理,分析上面例子C:

第一個(gè)變量b的自身對(duì)齊值為1,指定對(duì)齊值為2,所以,其有效對(duì)齊值為1,假設(shè)C從0x0000開始,那么b存放在0x0000,符合0x0000%1=0;  

第二個(gè)變量,自身對(duì)齊值為4,指定對(duì)齊值為2,所以有效對(duì)齊值為2,所以順序存放在0x0002、0x0003、0x0004、0x0005四個(gè)連續(xù)字節(jié)中,符合0x0002%2=0。

第三個(gè)變量c的自身對(duì)齊值為2,所以有效對(duì)齊值為2,順序存放在0x0006、0x0007中,符合0x0006%2=0。所以從0x0000到0x00007共八字節(jié)存放的是C的變量。  

又C的自身對(duì)齊值為4,所以C的有效對(duì)齊值為2。又8%2=0,C只占用0x0000到0x0007的八個(gè)字節(jié)。所以sizeof(struct C)=8.

字節(jié)對(duì)齊對(duì)程序的影響

先讓我們看幾個(gè)例子吧(32bit,x86環(huán)境,gcc編譯器):  

設(shè)結(jié)構(gòu)體如下定義:

現(xiàn)在已知32位機(jī)器上各種數(shù)據(jù)類型的長(zhǎng)度如下:  

char:1(有符號(hào)無符號(hào)同)  

short:2(有符號(hào)無符號(hào)同)  

int:4(有符號(hào)無符號(hào)同)  

long:4(有符號(hào)無符號(hào)同)  

float:4 double:8  

那么上面兩個(gè)結(jié)構(gòu)大小如何呢?  

結(jié)果是:  

sizeof(strcut A)值為8  

sizeof(struct B)的值卻是12  

結(jié)構(gòu)體A中包含了4字節(jié)長(zhǎng)度的int一個(gè),1字節(jié)長(zhǎng)度的char一個(gè)和2字節(jié)長(zhǎng)度的short型數(shù)據(jù)一個(gè),B也一樣;按理說A,B大小應(yīng)該都是7字節(jié)。之所以出現(xiàn)上面的結(jié)果是因?yàn)榫幾g器要對(duì)數(shù)據(jù)成員在空間上進(jìn)行對(duì)齊。上面是按照編譯器的默認(rèn)設(shè)置進(jìn)行對(duì)齊的結(jié)果,那么我們是不是可以改變編譯器的這種默認(rèn)對(duì)齊設(shè)置呢,當(dāng)然可以.例如:

sizeof(struct C)值是8。  

修改對(duì)齊值為1:

sizeof(struct D)值為7。  

后面我們?cè)僦v解#pragma pack()的作用.

2.2修改編譯器的默認(rèn)對(duì)齊值

1>在VC IDE中,可以這樣修改:[Project]|[Settings],c/c++選項(xiàng)卡Category的Code Generation選項(xiàng)的Struct Member Alignment中修改,默認(rèn)是8字節(jié)。  

2>在編碼時(shí),可以這樣動(dòng)態(tài)修改:#pragma pack .注意:是pragma而不是progma.

如果在編程的時(shí)候要考慮節(jié)約空間的話,那么我們只需要假定結(jié)構(gòu)的首地址是0,然后各個(gè)變量按照上面的原則進(jìn)行排列即可,基本的原則就是把結(jié)構(gòu)中的變量按照 類型大小從小到大聲明,盡量減少中間的填補(bǔ)空間.還有一種就是為了以空間換取時(shí)間的效率,我們顯示的進(jìn)行填補(bǔ)空間進(jìn)行對(duì)齊,比如:有一種使用空間換時(shí)間做 法是顯式的插入reserved成員:

reserved成員對(duì)我們的程序沒有什么意義,它只是起到填補(bǔ)空間以達(dá)到字節(jié)對(duì)齊的目的,當(dāng)然即使不加這個(gè)成員通常編譯器也會(huì)給我們自動(dòng)填補(bǔ)對(duì)齊,我們自己加上它只是起到顯式的提醒作用.

2.3字節(jié)對(duì)齊可能帶來的隱患

代碼中關(guān)于對(duì)齊的隱患,很多是隱式的。比如在強(qiáng)制類型轉(zhuǎn)換的時(shí)候。例如:

最后兩句代碼,從奇數(shù)邊界去訪問unsignedshort型變量,顯然不符合對(duì)齊的規(guī)定。  

在x86上,類似的操作只會(huì)影響效率,但是在MIPS或者sparc上,可能就是一個(gè)error,因?yàn)樗鼈円蟊仨氉止?jié)對(duì)齊.  

如果出現(xiàn)對(duì)齊或者賦值問題首先查看  

1). 編譯器的big little端設(shè)置  

2). 看這種體系本身是否支持非對(duì)齊訪問  

3). 如果支持看設(shè)置了對(duì)齊與否,如果沒有則看訪問時(shí)需要加某些特殊的修飾來標(biāo)志其特殊訪問操作。  

ARM下的對(duì)齊處理  

from DUI0067D_ADS1_2_CompLib type qulifiers  

有部分摘自ARM編譯器文檔對(duì)齊部分對(duì)齊的使用:  

1).__align(num)  

這個(gè)用于修改最高級(jí)別對(duì)象的字節(jié)邊界。在匯編中使用LDRD或者STRD時(shí)就要用到此命令__align(8)進(jìn)行修飾限制。來保證數(shù)據(jù)對(duì)象是相應(yīng)對(duì)齊。這個(gè)修飾對(duì)象的命令最大是8個(gè)字節(jié)限制,可以讓2字節(jié)的對(duì)象進(jìn)行4字節(jié)對(duì)齊,但是不能讓4字節(jié)的對(duì)象2字節(jié)對(duì)齊。__align是存儲(chǔ)類修改,他只修飾最高級(jí)類型對(duì)象不能用于結(jié)構(gòu)或者函數(shù)對(duì)象。  

2).__packed  

__packed是進(jìn)行一字節(jié)對(duì)齊  

  • 不能對(duì)packed的對(duì)象進(jìn)行對(duì)齊
  • 所有對(duì)象的讀寫訪問都進(jìn)行非對(duì)齊訪問
  • float及包含float的結(jié)構(gòu)聯(lián)合及未用__packed的對(duì)象將不能字節(jié)對(duì)齊
  • __packed對(duì)局部整形變量無影響
  • 強(qiáng)制由unpacked對(duì)象向packed對(duì)象轉(zhuǎn)化是未定義,整形指針可以合法定義為packed。

__packed int* p; //__packed int 則沒有意義

2.4對(duì)齊或非對(duì)齊讀寫訪問帶來問題

__packed struct STRUCT_TEST
{char a;int b;char c;
} ;
//定義如下結(jié)構(gòu)此時(shí)b的起始地址一定是不對(duì)齊的,在棧中訪問b可能有問題,因?yàn)闂I蠑?shù)據(jù)肯定是對(duì)齊訪問[from CL]
//將下面變量定義成全局靜態(tài)不在棧上
static char* p;static struct STRUCT_TEST a;void Main()
{
__packed int* q; //此時(shí)定義成__packed來修飾當(dāng)前q指向?yàn)榉菍?duì)齊的數(shù)據(jù)地址下面的訪問則可以
p = (char*)&a;
q = (int*)(p+1);
*q = 0x87654321; /*
得到賦值的匯編指令很清楚
ldr r5,0x20001590 ; = #0x12345678
[0xe1a00005] mov r0,r5
[0xeb0000b0] bl __rt_uwrite4 //在此處調(diào)用一個(gè)寫4byte的操作函數(shù)
[0xe5c10000] strb r0,[r1,#0] //函數(shù)進(jìn)行4次strb操作然后返回保證了數(shù)據(jù)正確的訪問
[0xe1a02420] mov r2,r0,lsr #8
[0xe5c12001] strb r2,[r1,#1]
[0xe1a02820] mov r2,r0,lsr #16
[0xe5c12002] strb r2,[r1,#2]
[0xe1a02c20] mov r2,r0,lsr #24
[0xe5c12003] strb r2,[r1,#3]
[0xe1a0f00e] mov pc,r14
*/ /*
如果q沒有加__packed修飾則匯編出來指令是這樣直接會(huì)導(dǎo)致奇地址處訪問失敗
[0xe59f2018] ldr r2,0x20001594 ; = #0x87654321
[0xe5812000] str r2,[r1,#0]
*/
//這樣可以很清楚的看到非對(duì)齊訪問是如何產(chǎn)生錯(cuò)誤的
//以及如何消除非對(duì)齊訪問帶來問題
//也可以看到非對(duì)齊訪問和對(duì)齊訪問的指令差異導(dǎo)致效率問題
}


責(zé)任編輯:龐桂玉 來源: C語(yǔ)言與C++編程
相關(guān)推薦

2020-08-05 12:17:00

C語(yǔ)言代碼分配

2023-11-15 13:15:52

C語(yǔ)言結(jié)構(gòu)體

2022-08-19 14:38:52

C語(yǔ)言結(jié)構(gòu)體struct

2022-07-28 12:17:36

C語(yǔ)言typedef#define

2010-08-16 13:03:27

DIV

2020-03-30 09:22:36

C語(yǔ)言結(jié)構(gòu)體

2010-01-12 15:24:48

C++語(yǔ)言

2023-08-26 11:36:31

Java框架Spring

2010-01-15 17:38:37

C++語(yǔ)言

2020-11-05 13:00:07

C語(yǔ)言編程語(yǔ)言

2020-02-04 14:53:22

git前端小抄

2023-11-22 13:40:17

C++函數(shù)

2011-07-20 10:06:54

CC++const

2017-03-10 10:16:37

PythonRequests庫(kù)

2024-10-28 21:02:36

消息框應(yīng)用程序

2022-07-03 08:06:40

JavaScript語(yǔ)言代碼

2021-06-08 11:54:45

語(yǔ)言CPU指令集

2024-01-02 15:41:04

CythonPython語(yǔ)言

2020-12-09 10:55:25

ArrayvectorLinux

2010-07-13 15:34:09

Perl語(yǔ)言
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

91在线短视频| 日韩视频在线免费| 美女福利视频在线| 国产精品四虎| 国产一区二区三区免费| 97欧美精品一区二区三区| 亚洲性猛交xxxx乱大交| 久久久久久亚洲精品美女| 精品毛片三在线观看| 亚洲国产精品综合| 欧美一区二区黄片| 免费人成网站在线观看欧美高清| 欧美极品美女电影一区| 精品人妻无码一区| 成人精品毛片| 欧美丰满美乳xxx高潮www| 国产黄色片免费在线观看| 超碰免费97在线观看| 国产盗摄女厕一区二区三区| 国产精品av电影| 久久亚洲AV无码| 水蜜桃久久夜色精品一区| 亚洲成人性视频| 91小视频在线播放| 欧美在线极品| 亚洲综合色成人| 正在播放一区| 成人性生交大片免费看午夜| av午夜一区麻豆| 亚洲最大福利网| 亚洲天堂视频网| 美女精品一区| 午夜精品视频网站| 青青草手机视频在线观看| 精品久久久久中文字幕小说| 亚洲国产成人精品女人久久久| 久久久精品视频国产| 78精品国产综合久久香蕉| 欧美午夜视频在线观看| 野外做受又硬又粗又大视频√| 精品黄色免费中文电影在线播放| 国产日韩欧美电影| 欧美福利一区二区三区| 欧美自拍偷拍第一页| 国产91色综合久久免费分享| 91精品国产综合久久久久久久久 | 欧美精品一区二区三区精品| 亚洲精品福利在线| 国产a√精品区二区三区四区| 成人在线视频区| 91精品久久久久久久99蜜桃| 中文字幕成人在线视频| 国产a亚洲精品| 欧美性欧美巨大黑白大战| 久久久精品在线视频| 桃色av一区二区| 岛国av一区二区三区| 免费国产黄色网址| 欧美男人天堂| 色88888久久久久久影院按摩 | 久久精品波多野结衣| 欧美一区二区| 欧美极品欧美精品欧美视频| 日本五十路女优| 亚洲一区国产| 国产成人在线一区二区| 中文字幕欧美色图| 久久99国产精品免费网站| 成人黄色影片在线| a级片免费视频| 国产suv一区二区三区88区| 动漫精品视频| 青青草视频在线免费观看| 久久久综合激的五月天| 蜜桃狠狠色伊人亚洲综合网站| 日本一区高清| 欧美国产精品一区| 中文字幕中文字幕一区三区| av毛片在线播放| 亚洲国产va精品久久久不卡综合| 国产成人无码精品久久久性色| 黑人巨大精品| 欧美日韩一区二区三区在线| 午夜诱惑痒痒网| 国产精品xxx在线观看| 亚洲免费精彩视频| 国产探花视频在线| 欧美日韩伊人| 国产成人免费av| 国产美女主播在线观看| 99这里只有精品| 性刺激综合网| 日本三级在线观看网站| 欧美日韩美女在线| 国产aⅴ爽av久久久久| 澳门久久精品| 色偷偷av亚洲男人的天堂| 欧美黑人精品一区二区不卡| 男女精品网站| 官网99热精品| 77777影视视频在线观看| 一区二区高清在线| 爆乳熟妇一区二区三区霸乳| 一本一道久久a久久| 夜夜躁日日躁狠狠久久88av| 久草网在线观看| 麻豆精品国产传媒mv男同| 国产高清自拍99| 调教视频免费在线观看| 五月天亚洲婷婷| 欧美高清精品一区二区| 国产精品欧美三级在线观看| 国内精久久久久久久久久人| 一级特黄aaa大片在线观看| 99久久99久久久精品齐齐| 伊人久久大香线蕉午夜av| 成人一区福利| 精品国产一区久久| 成年人网站在线观看视频| 亚洲一区欧美二区| 91精品久久久久久蜜桃| 999国产在线视频| 欧美性感美女h网站在线观看免费| 一级黄色免费毛片| 91麻豆国产自产在线观看亚洲| 欧美在线视频在线播放完整版免费观看| 国产亲伦免费视频播放| 国产精品女上位| 北条麻妃视频在线| 麻豆一区二区| 欧美激情伊人电影| 精品人妻少妇嫩草av无码专区| 欧美国产精品专区| 91香蕉视频污版| 伊人久久大香线蕉综合网站| 久久久爽爽爽美女图片| 亚洲乱码国产乱码精品精软件| 中文字幕中文乱码欧美一区二区| 国产免费又粗又猛又爽| 自拍偷拍精品| 日本a级片电影一区二区| 日韩一卡二卡在线| 亚洲福利视频一区| 性猛交╳xxx乱大交| 欧美色图麻豆| 国产精品裸体一区二区三区| 50度灰在线| 欧美一区二视频| 青青草国产在线观看| 国产精品一区二区视频| 亚洲国产一二三精品无码 | 久久国产精品亚洲77777| 激情五月综合色婷婷一区二区 | 悠悠资源网久久精品| 国产精品对白一区二区三区| 欧美hdxxxxx| 欧美精品一区二区三区很污很色的| 久久精品国产亚洲av香蕉| 成人小视频在线观看| 欧美一级免费播放| 日韩高清一级| 国产福利精品在线| 91在线观看| 日韩一二三四区| 日韩久久久久久久久| 91网站最新网址| 密臀av一区二区三区| 日韩欧美视频| 3d动漫啪啪精品一区二区免费| 久久香蕉av| 亚洲乱码一区av黑人高潮| 国产在线观看第一页| 亚洲国产成人午夜在线一区| 中文字幕 欧美日韩| 午夜日韩福利| 久久久久资源| 精品176极品一区| 欧美另类高清videos| 日韩一区二区三区不卡| 欧美最猛黑人xxxxx猛交| 三级av在线免费观看| 懂色av一区二区在线播放| 久久久免费视频网站| 水蜜桃久久夜色精品一区| 超碰97在线人人| 老司机2019福利精品视频导航| 色综合伊人色综合网| 粉嫩av一区二区夜夜嗨| 色偷偷久久一区二区三区| 黑人狂躁日本娇小| 99在线热播精品免费| 99sesese| 制服诱惑一区二区| 中文字幕中文字幕一区三区| 奇米777国产一区国产二区| 国产精品视频免费在线观看| 日本在线视频www鲁啊鲁| 亚洲无av在线中文字幕| 亚洲va久久久噜噜噜无码久久| 日本精品视频一区二区三区| 欧美日韩一级大片| 国产精品午夜久久| 少妇一级淫免费观看| 久久爱www久久做| 免费看一级大黄情大片| 一区二区电影| 亚洲精品免费在线看| 清纯唯美亚洲经典中文字幕| 亚洲自拍另类欧美丝袜| 日韩欧美少妇| 午夜精品久久久久久99热软件 | 自拍偷拍国产精品| 亚洲午夜久久久久久久久红桃| 国产精品综合av一区二区国产馆| 免费看国产黄色片| 国产精品综合| 拔插拔插海外华人免费| 欧美福利电影在线观看| 在线视频福利一区| 国产欧美一区二区精品久久久| 国产精品免费在线| 欧美9999| 91亚洲永久免费精品| 韩国理伦片久久电影网| 国产91色在线| 亚洲欧美电影| 2019精品视频| 国产精品偷拍| 久久91精品国产91久久跳| 日本在线观看免费| 中文字幕日韩av综合精品| 女人天堂在线| 亚洲欧美日韩在线一区| 亚洲色图狠狠干| 亚洲国产精品系列| 粉嫩av一区二区夜夜嗨| 日韩一级在线观看| 国产三级漂亮女教师| 欧美精品一级二级三级| 亚洲一线在线观看| 欧美日韩国产综合草草| 自拍偷拍第八页| 欧美色区777第一页| 日本成人一级片| 欧美综合在线视频| 在线观看中文字幕2021| 欧美日韩在线三级| 国产又粗又猛又黄又爽| 欧美肥胖老妇做爰| 国产精品一区二区黑人巨大| 4438x亚洲最大成人网| 国产精品亚洲欧美在线播放| 91精品国产品国语在线不卡| a视频免费在线观看| 欧美va亚洲va在线观看蝴蝶网| 欧美一区二区三区激情| 亚洲精品视频网上网址在线观看| 青青草免费在线| 国产一区二区三区在线免费观看 | 国产精品网站在线播放| 亚洲色图27p| 亚洲情趣在线观看| 豆国产97在线 | 亚洲| 偷拍一区二区三区| 中文字幕在线日本| 3d动漫精品啪啪一区二区竹菊| 国产av精国产传媒| 亚洲国产福利在线| 国产视频三级在线观看播放| 日韩一区二区福利| 深夜国产在线播放| 7777免费精品视频| 成人在线黄色| 99一区二区| 免费电影一区二区三区| 一区二区三区四区欧美| 欧美三级黄美女| 日本三区在线观看| 国产精品综合在线视频| 日韩精品一区二区三区高清免费| 国产人久久人人人人爽| 在线看的片片片免费| 香港成人在线视频| 国产美女www| 日韩丝袜美女视频| 韩国三级av在线免费观看| 久久亚洲一区二区三区四区五区高| 国产嫩草在线视频| 国产精品美女网站| 日韩免费一级| 日本视频一区在线观看| 欧美二区视频| 污污动漫在线观看| 成人精品小蝌蚪| 特黄一区二区三区| 同产精品九九九| 国产精品视频在线观看免费| 日韩风俗一区 二区| 黄色成年人视频在线观看| 欧美孕妇孕交黑巨大网站| 精品视频在线一区| 日本一区二区精品| 韩国av一区| 在线观看国产福利| 91麻豆国产香蕉久久精品| 日韩一级片大全| 欧美中文字幕一区| 五月天丁香视频| 久久av在线看| 国产极品嫩模在线观看91精品| 精品日产一区2区三区黄免费| 91九色精品国产一区二区| heyzo国产| 成人免费看的视频| 亚洲欧美精品aaaaaa片| 在线亚洲免费视频| 色播色播色播色播色播在线| 欧美国产日韩视频| 亚洲国产一区二区久久| 日本精品一区二区三区高清 久久 日本精品一区二区三区不卡无字幕 | 91精品久久久久久综合乱菊 | 国产视频1区2区| 亚洲成人网在线观看| 2020国产在线视频| 国产人妖伪娘一区91| 经典一区二区| 欧美韩国日本在线| 91免费精品国自产拍在线不卡| 久草中文在线视频| 日韩精品最新网址| 91香蕉在线观看| 亚洲a成v人在线观看| 手机亚洲手机国产手机日韩| 亚洲第一狼人区| 亚洲国产精品精华液ab| 无码人妻av免费一区二区三区| 日韩高清av在线| 自拍偷拍欧美视频| 欧美精品欧美精品| 久久精品男女| 日本xxxxxxxxx18| 在线一区二区三区做爰视频网站| 男人天堂网在线观看| 欧洲成人免费aa| 午夜精品福利影院| 东京热加勒比无码少妇| 久久精品亚洲精品国产欧美| 亚洲熟女综合色一区二区三区| 日韩精品欧美激情| 极品美女一区| 视频一区二区综合| 日本aⅴ免费视频一区二区三区| 亚洲午夜精品久久久久久高潮| 在线观看精品一区| 欧美jizzhd欧美| 亚洲一区二区在线| 国内精品99| 国产精品无码一区二区三区免费| 欧美午夜激情在线| 成人免费视频| 91九色视频在线| 伊人久久婷婷| 一级黄色片大全| 欧美日韩精品一区二区三区蜜桃| 黄色动漫在线| 国产精品一码二码三码在线| 国产精品久久久久久久免费软件| 蜜桃av免费看| 制服.丝袜.亚洲.另类.中文 | 亚洲一二三四区不卡| 日韩一级片免费| 国产精品久久久久久中文字| 一区二区三区在线电影| 少妇精品无码一区二区三区| 日韩欧美aaa| 麻豆网站在线免费观看| 国产精品对白一区二区三区 | 久久人人爽人人片| 亚洲午夜av在线| 国产福利电影在线| 99精品欧美一区二区三区| 国产亚洲在线| 极品美妇后花庭翘臀娇吟小说| 精品福利一区二区三区| 国产精品字幕| 国产夫妻自拍一区| 日本一区二区免费在线| www.日韩在线观看| 国产不卡精品视男人的天堂| 午夜精品久久99蜜桃的功能介绍| 37p粉嫩大胆色噜噜噜| 这里是久久伊人| 在线看的毛片| 国产在线无码精品| 国产日韩欧美制服另类| www.色呦呦| 国产狼人综合免费视频| 亚洲第一伊人| 永久免费看片视频教学| 亚洲欧美另类在线观看|