• <em id="6vhwh"><rt id="6vhwh"></rt></em>

    <style id="6vhwh"></style>

    <style id="6vhwh"></style>
    1. <style id="6vhwh"></style>
        <sub id="6vhwh"><p id="6vhwh"></p></sub>
        <p id="6vhwh"></p>
          1. 国产亚洲欧洲av综合一区二区三区 ,色爱综合另类图片av,亚洲av免费成人在线,久久热在线视频精品视频,成在人线av无码免费,国产精品一区二区久久毛片,亚洲精品成人片在线观看精品字幕 ,久久亚洲精品成人av秋霞

            字節序、字節對齊的理解

            更新時間:2023-05-28 08:16:17 閱讀: 評論:0

            匠心精神作文-定房

            字節序、字節對齊的理解
            2023年5月28日發(作者:矛盾糾紛排查化解工作情況匯報)

            1 前言

            作為一名 C/C++ 程序員,字節是我們天天都要與之打交道的一個東西。我們和

            它熟稔到幾乎已經忘記了它的存在。可是,它自己是不甘寂寞的,或遲或早地,

            總會在某些時候探出頭 來張望,然后給你一個腿兒絆。其實,只要你真正了解

            了它的底細,你就會暢行無阻。在本文中,我們將首先簡要了解一下字節的概念,

            然后著重了解一下字節序問 題和字節對齊問題。

            2 什么是字節

            我們知道,二進制計算機(也就是我們目前接觸到的幾乎所有的計算機)的最小

            數據單位是位( bit )。一位數據只能夠表示兩種含義(需要說明,盡管我們

            通常把單個位表示的兩種含義選擇為相互對立的含義,但這并不是必然的,例如

            你可以認為 1 代表 5 個人, 0 代表 8 個人)對于絕大多數的計算要求,

            個位顯然不能滿足。因此,我們通常都會使用一連串的位,我們可以稱之為位串

            bit string 請愛好質疑的的朋友注意,此術語非我杜撰)由于種種原因,

            計算機系統都不會讓你使用任意長度的位串,而是使用某個特定長度的位串。

            些常見的位串長度 形式具有約定好的名稱,如,半字節( nibble ,貌似用的

            不多)代表四個位的組合,字節( byte ,主角出場!)代表 8 個位的組合。

            再多的還有,字( word )、雙字( Double word ,通常簡寫為 Dword )、四

            Quad word 經常簡寫為 Qword 十字節 Ten byte 也簡寫為 Tbyte

            在這些里面,字( word )有時表示不同的含義。在 Intel 體系里, word

            示一個 16 位的數值,它是固定大小的。而在另外一些場合, word 表示了 CPU

            一次可處理的數據的位數,表示一個符合 CPU 字長 word-length 的數目的

            位串。事實上我們接觸較多的 ARM 體系中, word 就有不同的含義,它表示一

            32 位的數據(與機器字長相同),對于 16 位大小的數據, ARM 使用了另

            外的一個術語,叫作半字( half-word ),請大家在文檔閱讀時加以注意。另

            外, Qword 也是 Intel 體系中的術語,其他的體系中可能并不使用。在本文中,

            我們按照 Intel 的慣例來使用字或者 word 這一術語。

            一個字節中共有 8 個數據位,有時需要用圖表逐位表述各個位。習慣上,我們

            按照下面的圖來排列各個位的順序,即,按照從右到左的順序,依次為最低位(從

            0 位開始)到最高位(對于字節,則是第 7 位):

            字節是大多數現代計算機的最小存儲單元,但這并不代表它是計算機可以最高效

            地處理的數據單位。一般的來說,計算機可以最高效地處理的數據大小,應該

            其字長相同。在目前來講,桌面平臺的處理器字長正處于從 32 位向 64 位過渡

            的時期,嵌入式設備的基本穩定在 32 位,而在某些專業領域(如高端顯卡),

            處理器字長早已經達到了 64 位乃至更多的 128 位。

            3 字節序問題的由來

            對于字、雙字這些多于一個字節的數據,如果把它們放置到內存中的某個位置上,

            可以看出,我們還可以將之看作是字節的序列。一個字是兩個字節,雙字則

            四個字節。假設有以下數據: 0x12345678 0x9abcdef0 。在此處,我使用了

            我們最習慣的十六進制表示法,并給出了兩個雙字的值。按照慣例,我把雙字的

            左側視為高端,而把右側視為低端。把它們順序放置在起始地址 0 的內存中,

            如下圖所示:

            由圖示可知, 0x9abcdef 的相應地址為 0x04 。現在,問題來了,如果有一個

            內存操作,要從地址 0x06 處讀取一個字,得到的結果是多少呢?答案是:不一

            定。

            這里的本質問題在于,如何把多字節的對象存儲到內存中去呢?即使使用最正常

            的思維去考慮這個問題,你也會發現有兩種方法。第一種方法是,把最低端的

            節放到指定的起始位置(即基地址處)然后按照從低到高的字節順序把其余字

            節依次放入,如下圖 a ;另一種方法非常類似,但是對高端字節和低端字節的

            處理順序正好相反,如下圖 b (我確信你還可以想出其他的方法,但是除二字

            節的情況外,必然會打破字節排列順序的一致性,我視之為反常規思維的產物,

            此處暫不考慮)。

            a

            b

            在很久之前,哪一種存儲方式更為合理曾經有過爭論。到今天,爭論的結果已經

            無關緊要了,緊要的是以下事實:這兩種存儲方式都被應用到了現實的計算機

            統中。上圖 a 中的排列方式為 Intel 所采用并大行其道,而圖 b 的排列方式

            則被大多數的其他平臺采用(如最近被蘋果公司徹底拋棄的 PowerPC ),因此

            上,我們不能稱之為罕見的用法。之所以造成事實上的不經常見到,其原因正如

            我今天中午所得到的消息: Intel CPU 占整個市場份額的 80% 以上。

            這兩種排列方式通常用小端( little endian )和大端( big endian )來稱

            謂。這兩個奇怪的名字據說來源于童話《格列佛游記》,其中小人國里的公民為

            了雞蛋到底是應該從小的一頭打開還是大的一頭打開而大起爭執。 Intel 的方

            式對應于“小端”,順便說一句,大端的方式也有一個大公司的名字作為其代表,

            即最近開始沒落的 Motorola 如果有誰了解過 TIFF 圖像文件格式,就會發現

            其文件頭中用以標識文件數據字節序的標志就是“ II ”和“ MM ”,分別對應

            Intel Motorola 的首字母。值得提醒一下,小端方式的排列與位的排列

            順序相一致,看上去似乎更協調一些。

            現在我們可以回答上面的問題了。對于小端字節序,我們取到的字,其值為

            0x9abc ,而如果是大端字節序的話,就會取到 0xdef0

            4 何時會出現字節序問題

            字節序問題主要出現在數據在不同平臺之間進行交換時,交換的途徑可能是網絡

            傳輸,也可能是文件復制。例如,如果你設計了一種可能會應用于不同平臺的

            件格式,其中存儲了某些數據結構,則對于大小大于一個字節的數據就要明確地

            規定其遵循的字節序,以便各平臺上的處理程序可以在使用數據時實現做必要的

            換。

            舉一個實際的例子。 Java 是一個跨平臺的編程語言,其可執行文件(擴展名

            .class 使用的是一種機器無關的字節碼指令集)在理論上可以運行于所有

            的實現了 Java 運行時的平臺(包含有與特定平臺相關特性的除外)。編譯后

            .class 中一定保存有諸如 Integer 這樣類型的數據,這就涉及到了字節序

            的確定,否則 .class 必然不能被采用了不同字節序的平臺同時正確加載并運行。

            事實上, Java 語言采用的為大端字節序,這個一點都不奇怪,因為當初 SUN

            司自己的 SPARC 架構就是采用的大端字節序。同樣的問題和解決問題的方式,

            也存在于操作系統新貴 android 系統上。

            網絡傳輸則是另一個典型場景。 TCP/IP 所采用的網絡傳輸字節序標準也是大端

            字節序,這個也不必奇怪,因為 TCP/IP 是從 UNIX 系統發展起來的,而絕大部

            分的 UNIX 系統在很長的一段時間內都沒有運行于 Intel 體系架構上的版本。

            處理字節序問題的手段非常簡單,也就是對數據進行必要的轉換:將十六進制的

            數字從兩端開始交換,直至移動到數據的中心,交換完成為止。交換的結果就好

            像物體與鏡面之內的成像互換了位置,因此也被稱為鏡像交換( mirror-image

            swap )。請參看下圖:

            5 如何在程序中判斷字節序

            在實際的工作中,有時需要對字節序進行判斷,然后予以不同的處理。一般的來

            說,編譯后的程序通常只能運行在特定的平臺之上,其所采用的字節序方式在

            譯時即可確定,在這種情況下,程序源代碼中通常是把字節序的判別作為條件編

            譯的判斷語句,而不會判斷代碼放在真正的可執行代碼中。

            在這里,需要使用我們的老朋友 —— 宏。以下是一個真實的跨平臺工程中代碼,

            清晰起見,我稍做了修改:

            #define SGE_LITTLE_ENDIAN 1234

            #define SGE_BIG_ENDIAN 4321

            #ifndef SGE_BYTEORDER

            #if defined(__hppa__) ||

            defined(__m68k__) || defined(mc68000) || defined(_M_M68K) ||

            (defined(__MIPS__) && defined(__MISPEB__)) ||

            defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) ||

            defined(__sparc__)

            #define SGE_BYTEORDER SGE_BIG_ENDIAN

            #el

            #define SGE_BYTEORDER SGE_LITTLE_ENDIAN

            #endif

            #endif

            以上為根據平臺的預定義宏所作的前期工作,將之存入一個頭文件中,然后包含

            到源代碼文件中使用。

            在需要進行判斷的時候,則像以下代碼這樣使用:

            #if SGE_BYTEORDER == SGE_BIG_ENDIAN

            #define SwapWordLe(w) SwapWord(w)

            #el

            #define SwapWordLe(w) (w)

            #endif

            由于這兩個宏實際上被定義成了常量數值,因此也可以被用到可執行代碼中,

            行執行期的動態判斷:

            if(SGE_BYTEORDER == SGE_BIG_ENDIAN)

            return r << 16 | g << 8 | b;

            el

            return r | g << 8 | b << 16;

            追根尋源,上面的這種判斷需要依賴編譯器及其所在平臺的預定義宏。下面介紹

            一種執行期動態判斷的方法,則不需要有宏的參與,而是巧妙地利用了字節序的

            本質。代碼如下:

            int IsLittleEndian()

            {

            const static union

            {

            unsigned int i;

            unsigned char c[4];

            } u = { 0x00000001 };

            return u.c[0];

            }

            動手畫一下內存布局即可了解其原理。還有更簡練的寫法,作為練習,請大家自

            行去尋找。

            在結束對字節序的討論之前,特別提醒一下, ARM 體系的 CPU 在字節序上與

            Intel 的體系結構是一致的。

            6 字節對齊問題的產生

            馮諾依曼體系的計算機,通過地址總線來尋址內存(假設 n 為地址總線的位數,

            則最多可以尋址 2n 個內存位置)根據地址總線的位數,我們可以知道 CPU

            內存的一次交互(也即一次內存訪問)能夠讀寫的數據的大小。顯然地,對于 8

            位的 CPU ,是一個字節,對于 16 CPU 則是一個字, 32 CPU 則是一個

            雙字,依此類推。這是 CPU 與生俱來的最本質、最快捷的訪問方式。在實際的

            計算需求中,如果訪問的數據量超過了一次訪問的限度,則很顯然需要進行多次

            訪問,如果是少于的話,則需要對 從內存中取回的數據進行適當的裁剪。裁剪

            操作有可能是 CPU 自身支持的,也有可能是需要用軟件來實現的。

            有的系統是支持尋址到單個字節所在的位置的(稱為可字節尋址)而有的則不

            可以,只能尋址到符合某些條件的地址上。對于 Intel/ARM 體系結構的 CPU

            我們在宏觀上可以認為它們都支持字節尋址(但是 ARM 家族的 CPU 在內存訪問

            時有其他約束,下文有詳細敘述)。

            出現這樣的限制是有原因的,終極因素就在于內存訪問的粒度與字長的關聯上。

            32 CPU 來說,它對于地址為 4 的倍數處的內存訪問是最自然的,其余的

            地址就要做一些額外的工作。例如,我們要訪問地址為 0x03 處的一個雙字,

            80x86 體系,事實上將會導致 CPU 的兩次內存訪問,取回 0x00 以及 0x04

            處的兩個雙字,分別進行適當的截取之后再拼裝為一個雙字返回。對于其他的體

            系,設計者可能認為 CPU 不應該承擔數據拼裝的工作,因而就選擇產生一個硬

            件異常。

            在硬件和 / 或操作系統的約束下,進行數據訪問時對數據所在的起始位置以及

            數據的大小都需要遵循一定的規則 ,與這些規則相關的問題,都可以稱之為字

            節對齊問題。

            舉例來說。在 HP-UX (惠普公司的一個服務器產品平臺, UNIX 的一種)平臺

            中,系統嚴禁對奇地址直接進行訪問,假設你視這一原則于不顧:

            int i = 0; // 編譯器保證 i 的起始地址不是奇地址

            char c = *((char*)&i + 1); // 強制在奇地址處訪問

            其執行結果就是內核轉儲( core dump ),為應用程序最嚴重的錯誤。(特別

            注明:此處代碼為記憶中的情形,目前筆者已經沒有驗證環境了)

            在不同的硬件體系架構下,字節對齊關系到三方面的問題一是數據訪問的可行

            性問題,二是數據訪問的效率問題,三是數據訪問的正確性問題

            字節對齊問題給程序員在編碼時帶來了額外的注意點,并且對最終程序執行的正

            確性也帶來了一定的不確定因素。相同的代碼在不同的平臺上,甚至在相同的平

            臺上采用不同的編譯選項,都可能有不同的執行結果。

            如果所有的系統都和 HP-UX 的表現一樣的話,事情要簡單一些,問題通常會在

            比較早的時間內就可以暴露出來。遺憾的是,我們目前所面對的平臺不是這樣,

            這些平臺的設計者為最大程度地減 少對開發人員的干擾而作了辛苦的努力,使

            得我們在很多時候都感覺不到字節對齊問題的存在。但另一方面,也制造出了把

            問題隱藏得更深的機會。

            效果最好的努力是 Intel 的體系架構。 80x86 允許你對整個內存進行字節尋址,

            在不超過機器字長的情況下可以訪問任意數目的字節(很顯然,大多數情況下就

            1 字節、 2 字節、 3 字節、 4 字節這四種情況)。

            ARM 體系的 CPU 似乎做了一定的努力,但是其結果和其他體系相比呈現一種很

            奇怪的狀態。由于筆者沒有對 ARM 整個系列的 CPU 進行過完整的了解,因此此

            處的論述可能并不完整。 ARM CPU 允許對內存進行字節尋址,但在訪問時有額

            外的要求。即:如果你要訪問一個字(注意本文慣例,此處的字是兩字節大小,

            ARM 平臺的標準術語不同),那么起始地址必須在一個字的邊界上,如果訪

            問一個雙字,則起始地址必須位于一個雙字的邊界上(其余數據類型請參考 ARM

            的知識庫文檔)這意味著,你不能在 0x03 這樣的地址處訪問一個字或者一個

            雙字。但是,令人痛苦的事情到來了,如果你非要這么訪問,大多數的 CPU

            會有顯式的異常,而是返回錯誤的數據,其余的一些 CPU 則會造成程序崩潰。

            7 如何控制字節對齊

            控制程序的字節對齊行為是一個與編譯器相關的工作。以下編譯指示

            directive )被許多編譯器認可:

            #pragma pack(n)

            #pragma pack()

            任何處于這兩個編譯指示語句之間的數據結構,將采用 n 字節的數據對齊方式。

            n 是一個可以指定的數字,取值范圍請參閱所使用編譯器的文檔,通常都會取值

            2 的冪。現代編譯器在對程序進行編譯時,處于效率方面的考慮,會對數據

            結構的內存布局使用一個默認的字節對齊值,這個值一般都可以在命令行上顯式

            指定。如果 要在一個頭文件 / 源文件中對特定的部分指定對齊屬性,則需要上

            述的編譯指示。結束指示的寫法在某些編譯器或者平臺下需要寫成:

            #pragma pack(pop)

            我們用一個例子來看一下這兩個指示的實際效用,看它究竟是如何影響數據的內

            存排列的。假定我們有如下的數據結構定義:

            struct S1

            {

            int i;

            char c;

            short s;

            };

            struct S2

            {

            char c;

            int i;

            short s;

            };

            這兩個結構的成員看起來是一樣的,只不過換了一下順序而已。我們使用

            sizeof() 操作符來測量各自占用多少字節(除非特別指出,均在 32 位平臺上,

            并認為 int 占用 4 字節, char 占用 1 字節, short 占用 2 字節)。答案

            似乎不可思議, sizeof(S1) 的結果是 8 ,而 sizeof(S2) 卻是 12 。差異是

            怎么來的呢?原因就在于編譯器缺省的字節對齊設定在發生作用。

            這里需要引入以下概念和規則:

            概念及規則一,原生數據類型自身對齊值。原生數據類型即是 C/C++ 直接支持

            的數據類型,也可以稱為內建( built in )數據類型。它們的自身對齊值分別

            為: char 1 short int 2 int float double 等為 4 ,不

            受符號位(即正負)的影響。

            概念及規則二,用戶數據類型自身對齊值。用戶數據類型即由程序員定義的類、

            結構、聯合等,也叫抽象數據類型( ADT )。它們的自身對齊值等同于為其成

            員的對齊值中的最大值。

            概念及規則三,用戶指定對齊值。程序員在編譯器命令行上的指定值,或者在

            pragma pack 編譯指示中指定的值,對最終數據的影響取就近原則(顯然 pragma

            pack 指示會覆蓋命令行的指定)。

            概念及規則四,有效對齊值。取數據類型的自身對齊值與用戶指定對齊值中的較

            小值。此值一旦決出,則會影響到數據在內存中的布局。一個有效對齊值為 n

            表示以下事實:相關數據在內存中存放時,其起始地址的值必須可以被 n 整除

            根據以上四條,可以很圓滿地解釋 S1 S2 的大小不同這一現狀。由于沒有使

            pragma pack 指示,那么編譯器(在我的測試環境下)會采用缺省的對齊值 4

            假設 S1 或者 S2 的實例將從地址 0x0000 處開始。

            S1 中,第一個成員 i 的自身對齊值為 4 指定對齊值(盡管是缺省的)

            4 同時 0x0000 這一地址符合被 4 整除的要求,因此, i 將占據 0x0000

            0x0003 的四個字節,下一個可用地址值為 0x0004 ;接下來的成員 c 的數

            據類型為 char ,自身對齊值為 1 ,指定對齊值為 4 ,取較小者仍然是 1

            0x0004 符合被 1 整除的要求,因此 c 將占據 0x0004 處的一個字節,下一個

            可用地址值為 0x0005 最后的一個成員 s 數據類型為 short 自身對齊值為

            2 ,指定對齊值為 4 ,有效對齊值取 2 ,但是地址 0x0005 不能符合被 2

            除的要求,因此編譯器作相應調整,向后移動到最近的滿足要求的地址處,即

            0x0006 s 將占用 0x0006 0x0007 處的兩個字節,由此導致 S1 的大小為

            8

            在地址 0x0005 處的一個字節,習慣上稱之為填充數據( padding )。

            同理可以輕易推出 S2 結構的大小確實是 12 是這樣嗎?不是的。實際動手的

            結果應該是 10 。那么 12 應該作何解釋?

            我們來設想一個場景,程序員用 new 或者 malloc 分配一個 S2 的數組。不用

            多,假定有兩個元素,而地址 0x0000 處正好有空閑的內存可以滿足這一內存分

            配請求。我們都知道, C/C++ 語言中,數組的元素是緊鄰排放的。也就是說,

            后一個元素的起始地址應該正好等于前一個元素的起始地址,并加上元素的大小。

            我們來檢視一下 S2 的情況,它的元素大小為 10 ,它的有效對齊值是 4 (請

            參閱概念及規則二),這表示任何一個 S2 結構的起始地址都應該位于 4 的整

            數倍處。現實的情況是,第一個元素的起始地址是 0x0000 第二個元素的起始

            地址變成了 0x000A ,而后者的數值不能滿足被 4 整除的要求。正是為了解決

            這一情況,編譯器為 S2 結構在結尾處也增加了兩個字節的填充,從而滿足各個

            條件的限定。

            pragma pack 指示非常有效,使用也比較普遍,但是對于 ARM 平臺,它有一些

            力所不及的地方,我們再來看一個例子。仍然用 S2 這一次,我們強制把它的

            字節對齊設定為 1 ,并同時定義了 S2 的一個全局變量 s2 。也即:

            #pragma pack(1)

            struct S2

            {

            char c;

            int i;

            short s;

            } s2;

            #pragma pop()

            然后,在某處具有如下的數據訪問:

            int i = s2.i;

            這條看上去稀松平常的語句很可能不能如所希望的那樣執行。因為對于 i 的訪

            問其前提應該是 i 的起始地址是 4 的倍數(注意,這個不是對齊規則的約束結

            果,而是 ARM CPU 的數據訪問規則的約束結果),但強行指定的 1 字節對齊則

            導致 i 的起始地址是一個奇數。

            RVCT 編譯器為此做了特別的努力,引入了 __packed 關鍵字。此關鍵字應用到

            用戶定義數據結構上會導致該結構的內存布局取得與 pragma pack(1) 等同的

            效果,但是,更進一步地,編譯器會把對該結構中成員的訪問作適當的處理,

            現不對齊的訪問則會翻譯為調用適當的保證數據正確性的函數。此關鍵字也可

            以應用到指針上,以保證經由指針對目標對象的訪問也采用保守方式。可以預料

            到的是,此關鍵字的使用會降低代碼執行的效率,所以需要慎用,一個很典型的

            使用 場景是移植其他平臺的代碼時。以下是一些使用了此關鍵字的定義示例:

            typedef __packed struct

            {

            char x; // 所有成員都會被 __packed 修飾

            int y;

            } X; // 5 字節的結構,自身對齊值 = 1

            int f(X* p)

            {

            return p->y; // 執行一個非對齊的讀取操作

            }

            typedef struct

            {

            short x;

            char y;

            __packed int z; // __pack 本成員,此用法僅適用于整型

            char a;

            } Y; // 8 字節結構,自身對齊值 = 2(請思考原因)

            int g(Y* p)

            {

            return p->z + p->x; // 僅對 z 執行非對齊讀取操作

            }

            需要注意的是, GCCE 編譯器沒有實現類似的努力,它有一個和對齊有關的關鍵

            字: __attribute__ (packed)) ,該關鍵字的功效與 pragma pack(1) 類似。

            閱讀課教案-中隊長職責

            字節序、字節對齊的理解

            本文發布于:2023-05-28 08:16:16,感謝您對本站的認可!

            本文鏈接:http://www.newhan.cn/zhishi/a/1685232977182514.html

            版權聲明:本站內容均來自互聯網,僅供演示用,請勿用于商業和其他非法用途。如果侵犯了您的權益請與我們聯系,我們將在24小時內刪除。

            本文word下載地址:字節序、字節對齊的理解.doc

            本文 PDF 下載地址:字節序、字節對齊的理解.pdf

            標簽:qword
            相關文章
            留言與評論(共有 0 條評論)
               
            驗證碼:
            推薦文章
            排行榜
            Copyright ?2019-2022 Comsenz Inc.Powered by ? 實用文體寫作網旗下知識大全大全欄目是一個全百科類寶庫! 優秀范文|法律文書|專利查詢|
            主站蜘蛛池模板: 69精品丰满人妻无码视频a片| 国产成人午夜福利院| 久久亚洲私人国产精品| 日本熟妇浓毛| 久久九九精品国产免费看小说| 超级乱淫片午夜电影网福利| 亚洲高清成人av在线| 俄罗斯性孕妇孕交| 色综合久久中文字幕综合网| 国产超碰无码最新上传| 精品国产粉嫩内射白浆内射双马尾| 成人精品日韩专区在线观看| 国产精品人成视频免费国产| 亚洲人成无码网站18禁| 国产成人综合色就色综合| 美女啪啪网站又黄又免费| 蜜桃视频一区二区三区四| 婷婷色综合成人成人网小说 | 精品人妻中文字幕av| 91精品少妇一区二区三区蜜桃臀| 亚洲精品日本一区二区| 久久亚洲欧美日本精品| 中文字幕一区二区三区麻豆 | 自拍日韩亚洲一区在线| 国产精品爆乳奶水无码视频免费| 小嫩批日出水无码视频免费| 亚洲色偷偷偷综合网| 九九热在线这里只有精品| 人妻(高h)| 午夜福利精品一区二区三区| 精品午夜福利在线视在亚洲| 老色鬼永久精品网站| 国产一区二区内射最近更新| 狠狠色狠狠色综合日日不卡| 老司机久久99久久精品播放免费| 国产内射性高湖| A级日本乱理伦片免费入口| 欧美拍拍视频免费大全| 日本熟妇色xxxxx| 久久久久亚洲AV无码专| 亚洲一区在线成人av|