在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

什么是__attribute__?嵌入式C代碼屬性怎么定義?

Dp1040 ? 來源:漫談嵌入式 ? 2023-10-13 15:55 ? 次閱讀

嵌入式開發,離不開 C 語言,C語言中有很多語法會直接或間接影響你代碼的質量,下面就來講講__attribute__ 關鍵字的用法。

1. 什么是 __attribute__

GNU C 編譯器增加了一個 __attribute__ 關鍵字用來聲明一個函數、變量或類型的特殊屬性。申明這些屬性主要用途就是指導編譯程序進行特定方面的優化或代碼檢查。

__attrabute__ 的用法非常簡單,當我們定義一個一個函數、變量或者類型時,直接在他名字旁邊添加如下屬性即可:

__attribute__((ATTRIBUTE))

需要注意的是,__attribute__ 后面是兩對小括號,不能圖方便只寫一對,否則會編譯報錯。括號里的 ATTRIUBTE 表示要聲明的屬性,目前支持十幾種屬性聲明:

section:自定義段

aligned:對齊

packed:對齊

format:檢查函數變參格式

weak:弱聲明

alias:函數起別名

noinline:無內聯

always_inline:內聯函數總是展開

......

比如:

charc __attribute__((algined(8)))=4;
intglobal_val __attribute__((section(".data")));

當然,我們對一個變量也可以同時添加多個屬性。在定義變量前,各個屬性之間用逗號隔開。以下三種聲明方式是沒有問題的。

charc__attribute__((packed,algined(4)));
charc__attribute__((packed,algined(4)))=4;
__attribute__((packed,algined(4)))charc=4;

2. 屬性聲明:section

section 屬性的主要作用是:在程序編譯時,將一個函數或者變量放到指定的段,即指定的section 中。

一個可執行文件注意由代碼段,數據段、BSS 段構成。代碼段主要用來存放編譯生成的可執行指令代碼、數據段和BSS段用來存放全局變量和未初始化的全局變量。

除了這三個段,可執行文件還包含一些其他的段。我們可以用 readelf 去查看一個可執行文件各個section信息。

下表是不同的 section 及說明:

section 組成
代碼段(.text) 函數定義、程序語句
數據段 (.data) 初始化的全局變量、初始化的靜態局部變量
BSS 段(.bss) 未初始化的全局變量,未初始化的靜態局部變量

intglobal_val=8;
intunint_val;

intmain(void)
{
return0;
}

我們使用gcc 編譯這個程序:

gcc-m32-o a.out gnu.c

查看符表號信息:

#readelf-s a.out
Num:ValueSize TypeBindVisNdx Name
44:0804c0204OBJECTGLOBAL DEFAULT24unint_val
45:080490904FUNCGLOBAL HIDDEN13__x86.get_pc_thunk.bx
46:0804c0100NOTYPEWEAKDEFAULT23data_start
47:0804c01c0NOTYPEGLOBAL DEFAULT23_edata
48:080491c40FUNCGLOBAL HIDDEN14_fini
49:0804c0184OBJECTGLOBAL DEFAULT23global_val
50:0804c0100NOTYPEGLOBAL DEFAULT23__data_start
51:000000000NOTYPEWEAKDEFAULTUND __gmon_start__
52:0804c0140OBJECTGLOBAL HIDDEN23__dso_handle
53:0804a0044OBJECTGLOBAL DEFAULT15_IO_stdin_used
54:000000000FUNCGLOBAL DEFAULTUND __libc_start_main@@GLIBC_
55:0804916085FUNCGLOBAL DEFAULT13__libc_csu_init
56:0804c0240NOTYPEGLOBAL DEFAULT24_end
57:080490801FUNCGLOBAL HIDDEN13_dl_relocate_static_pie
58:0804904055FUNCGLOBAL DEFAULT13_start
59:0804a0004OBJECTGLOBAL DEFAULT15_fp_hw
60:0804c01c0NOTYPEGLOBAL DEFAULT24__bss_start
61:0804915210FUNCGLOBAL DEFAULT13main

查看 section 信息:

#readelf-S a.out


c1f7f0ea-699d-11ee-939d-92fbcf53809c.png

使用 __attribute__ ((section("xxx"))),修改段的屬性。

intglobal_val=0;
intunint_val __attribute__((section(".data")));

intmain()
{
return0;
}

可以看到 unint_val 這個變量,已經被編譯器放在數據段中。當然也可以自定義段的名稱。

c20d2d2a-699d-11ee-939d-92fbcf53809c.png

3. 屬性聲明:aligned

GNU C 通過 __attribute__ 來聲明 aligned 和 packed 屬性,指定一個變量或類型的對齊方式。

通過 aligned 屬性,我們可以顯示地指定變量 a 在內存中的地址對齊方式。aligned 有一個參數,表示要按幾個字節對齊,使用時要注意,地址對齊的字節數必須是 2 的冪次方,否則編譯就會報錯。

3.1 地址對齊

#include

inta=1;
intb=2;
charc1=3;
charc2=4;
intmain()
{
printf("a=%p
",&a);
printf("b=%p
",&b);
printf("c1=%p
",&c1);
printf("c2=%p
",&c2);

return0;
}

可以看到,char 占一個字節,c2的地址緊挨著 c1

a=0x404030
b=0x404034
c1=0x404038
c2=0x404039

使用 aligned 地址對齊

#include

inta=1;
intb=2;
charc1=3;
charc2\__attribute__((aligned(4)))=4;
intmain()
{
printf("a=%p
",&a);
printf("b=%p
",&b);
printf("c1=%p
",&c1);
printf("c2=%p
",&c2);

return0;
}

可以看到,c2 的地址是按照4字節對齊

a=0x404030
b=0x404034
c1=0x404038
c2=0x40403c

通過 aligned 屬性聲明,雖然可以顯示的指定變量地址的對齊方式,但是也會因為邊界對齊造成一定的內存空間浪費。

地址對齊的好處是,為了配合計算機硬件設計,可以簡化CPU和內存RAM之間的接口和硬件設計。

例如,一個32位的計算機操作系統,在CPU讀取內存時,硬件設計上可能只支持4字節或者4字節倍數對齊地址訪問,CPU 每次向 RAM 讀寫數據時,一個周期可以讀寫4字節。如果我們把一個int型數據就放在4字節對齊的地址上,那么CPU就可以一次性把數據讀取完畢,否則可能需要讀取兩次。

3.2 結構體對齊

結構體作為一種復雜的數據類型,編譯器在給一個結構體變量分配存儲空間時,不僅要考慮結構體內各個成員的對齊,還要考慮結構體整體的對齊。

為了結構體各成員對齊,編譯器可能會在結構體內填充一些字節。為了結構體的整體對齊,編譯器可能會在結構體的末尾一些空間。

#include

structdata{
chara;
intb;
short c;
};

intmain()
{
structdatas;
printf("size=%d
",sizeof(s));
printf("a=%p
",&s.a);
printf("b=%p
",&s.b);
printf("c=%p
",&s.c);

return0;
}

四字節對齊:占12字節

size=12
a=0xffb6c374
b=0xffb6c378
c=0xffb6c37c

結構體成員順序不同,所占大小有可能不同:

#include

structdata{
chara;
short b;
intc;
};

intmain()
{
structdatas;
printf("size=%d
",sizeof(s));
printf("a=%p
",&s.a);
printf("b=%p
",&s.b);
printf("c=%p
",&s.c);

return0;
}

四字節對齊:占8字節

size=8
a=0xffa2d9f8
b=0xffa2d9fa
c=0xffa2d9fc

顯示的指定成員的對齊方式:

#include

structdata{
chara;
short b __attribute__((aligned(4)));
intc;
};

intmain()
{
structdatas;
printf("size=%d
",sizeof(s));
printf("a=%p
",&s.a);
printf("b=%p
",&s.b);
printf("c=%p
",&s.c);

return0;
}

四字節對齊:占12字節

size=12
a=0xffb6c374
b=0xffb6c378
c=0xffb6c37c

顯示指定結構體對齊方式:

#include

structdata{
chara;
short b;
intc;
}__attribute__((aligned(16)));

intmain()
{
structdatas;
printf("size=%d
",sizeof(s));
printf("a=%p
",&s.a);
printf("b=%p
",&s.b);
printf("c=%p
",&s.c);

return0;
}

16字節對齊,末尾填充8字節:占16字節

size=16
a=0xffa2d9f8
b=0xffa2d9fa
c=0xffa2d9fc

3.3 編譯器一定會按照 aligend 指定的方式對齊嗎?

我們通過這個屬性聲明,其實只是建議編譯器按照這種大小地址對齊,但不能超過編譯器允許的最大值。一個編譯器,對每個基本的數據類型都有默認的最大邊界對齊字節數,如果超過了,則編譯器只能按照它規定的最大對齊字節數來對變量分配地址。

4. 屬性聲明:packed

aligned 屬性一般用來增大變量的地址對齊,元素之間地址對齊會造成一定的內存空洞,而packed屬性則正好相反,一般用來減少地址對齊,指定變量或類型使用最可能小的地址對齊方式。

顯示的對結構體成員使用packed

#include
structdata{
chara;
short b __attribute__((packed));
intc __attribute__((packed));
};
intmain()
{
structdatas;
printf("size=%d
",sizeof(s));
printf("a=%p
",&s.a);
printf("b=%p
",&s.b);
printf("c=%p
",&s.c);

return0;
}

使用最小一字節對齊:

size=7
a=0xfff38fb9
b=0xfff38fba
c=0xfff38fbc

對整個結構體添加packed屬性

structdata{
chara;
short b;
intc;
}__attribute__((packed));

內核中的packed、aligned 聲明

在內核源碼中,我們經常看到aligned 和 packed 一起使用,即對一個變量或者類型同時使用packed 和 aligned 屬性聲明。這樣做的好處是即避免了結構體各成員間地址對齊產生的內存空洞,又指定了整個結構體的對齊方式。

structdata{
chara;
short b;
intc;
}__attribute__((packed,aligned(8)));

5. 屬性聲明:format

GNU 通過 __attribute__ 擴展的 format 屬性,來指定變參函數的參數格式檢查。

它的使用方法如下:

__attribute__((format(archetype,string-index,frist-to-check)))
voidLOG(constchar*fmt,...)__attribute__((format(printf,1,2)));

屬性format(printf,1,2) 有3各參數,第一個參數pritnf 是告訴編譯器,按照printf的標準來檢查;第二個參數表示LOG()函數所有的參數列表中格式字符串的位置索引,第三個參數是告訴編譯器要檢查的參數的起始位置。

LOG("hello world,i am%d ages
",age);/*前者表示格式字符串,后者表示所有的參數*/

6. 屬性聲明:weak

GNU C 通過 weak 屬性聲明,可以將一個強符號,轉換為弱符號。使用方法如下:

void__attribute__((weak))func(void);
intnum __attribute__((weak));

在一個程序中,無論是變量名,還是函數名,在編譯器眼里,就是一個符號而已,符號可以分為強符號和弱符號。

強符號:函數名,初始化的全局變量名

弱符號:未初始化的全局變量名。

在一個工程項目中,對于相同的全局變量名、函數名,我們一般可以歸結為以下3種場景:

強符號 + 強符號

強符號 + 弱符號

弱符號 + 弱符號

強符號和弱符號主要用來解決在程序鏈接過程中,出現多個同名全局變量、同名函數的沖突問題,一般我們遵循以下3個原則:

一山不容二虎

強弱可以共處

體積大者勝出

在一個項目中,不可能同時存在兩個強符號。如果在一個多文件的項目中定義兩個同名的函數后者全局變量,那么連接器在鏈接時就會報重定義錯誤。

但是,在一個工程中允許強符號和弱符號同時存在,比如可以定義一個初始化的全局變量和一個未初始化的全局變量,這種寫法在編譯時是可以編過的。

編譯器對這種同名符號沖突時,在做符號決議時,一般會選擇強符號,丟掉弱符號。

還有一種情況是,在一個工程中,當都是弱符號時,那么編譯器該選擇哪個呢?誰在內存中存儲空間大,就選誰。

變量的弱符號與強符號

//func1.c
inta=1;
intb;
voidfunc(void)
{
printf("func.a=%d
",a);
printf("func.b=%d
",b);
}
//main.c
inta;
intb=2;
voidfunc();

intmain()
{
printf("main.a=%d
",a);
printf("main.b=%d
",b);
func();

return0;
}

編譯后,程序運行結果如下。可以看出打印的都是強符號的值。

main.a=1
main.b=2
func.a=1
func.b=2

一般不建議在一個工程中定義多個不同類型的同名弱符號,編譯時可能會出現各種各樣的問題。也不能同時定義兩個同名的強符號,否則會報重定義錯誤。我們可以使用GNU C 的擴展 weak 屬性,將一個強符號轉換為弱符號。

inta __attribute__((weak))=1;

函數的強符號與弱符號

鏈接器對于同名的函數沖突,同樣遵循相同的規則。函數名本身是一個強符號,在一個工程中定義兩個同名的函數,編譯器肯定會報重定義錯誤。但是,我們可以通過weak 屬性聲明,將其中的一個函數名轉換為弱符號。

//func1.c
inta __attribute__((weak))=1;
voidfunc(void)
{
printf("func.a=%d
",a);
}

//main.c
inta=4;
void__attribute__((weak))func(void)
{
printf("main.a=%d
",a);
}

intmain(void)
{
func();
return0;
}

弱符號的用途

在一個源文件中引用一個編號或者函數,當編譯器只看到聲明,而沒看到其定義時,一般編譯時不會報錯。在鏈接階段,鏈接器會到其他文件中找到這些符號的定義,若未找到,則報未定義錯誤。

當函數被聲明一個弱符號時,會有一個奇特地方:當鏈接器找不到這個函數的定義時,也不會報錯。編譯器會將這個函數名,即弱符號,設置為0或者一個特殊值。只有當程序運行時,調用到這個函數,跳轉到零地址或者一個特殊的地址才會報錯誤,產生一個內存錯誤。

如果我們在使用函數前,判斷這個函數地址是否為0,即可避免段錯誤。你會發現,即使函數未定義也可以正常編過。

弱符號的這個特性在庫函數開發設計中應用十分廣泛,如果在開發一個庫時,基礎功能已經實現,有些高級功能還未實現,那么你就可以將這些函數通過weak 屬性聲明轉換為一個弱符號。

7. 屬性聲明:alias

GNU C 擴展了一個 alias 屬性,這個屬性很簡單,主要用來給函數定義一個別名。

void__f(void)
{
printf("__f
");
}

voidf(void)__attribute__((alias("__f")));

intmain(void)
{
f();
return0;
}

Linux 內核中你會發現alias有時候會和weak屬性一起使用。如有些接口隨著內核版本升級,函數接口發生了變化,我們可以通過alias屬性對舊的接口名字進行封裝,重新起一個接口名字。

//f.c
void__f(void)
{
printf("__f
");
}

voidf()__attribute__((weak,alias("__f")));

//main.c
void__attribute__((weak))f(void);
voidf(void)
{
printf("f
");
}

intmain()
{
f();
return0;
}

如果我們在main.c 中定義了f()函數,那么main 函數調用f()會調用薪定義的函數,否則調用__f()函數。

8. 屬性聲明:noinline 和 always_inline

8.1 什么是內聯函數

說起內聯函數,就不得不說起函數調用開銷。一個函數在執行過程中,如果要調用其他函數,則一般會執行以下過程:

保存當前函數現場

跳到調用函數執行

恢復當前函數現場

繼續執行當前函數

對于一些短小精悍,并且調用頻繁的函數,調用開銷大,這個時候我們可以將函數聲明為內聯函數。編譯器遇到內聯函數會想宏一樣將內聯函數之間在調用處展開,這樣做就減少了函數調用的開銷。

8.2 內聯函數與宏

與宏相比,內聯函數有以下優勢:

參數類型檢查:內聯函數本質上還是一個函數,在編譯過程中編譯器會對齊進行參數檢查,而宏不具備這個特性。

便于調試:函數支持的調試功能有斷點、單步等。

返回值:內聯函數有返回值。這個優勢是相對于ANSI C 說的。因為現在的宏也有返回值和類型了,如使用語句表達式定義的宏。

接口封裝:有些內聯函數可以用來封裝一個接口,而宏不具備這個特性。

8.3 編譯器對內聯函數的處理

我們雖然可以通過inline 關鍵字將一個函數聲明為一個內聯函數,但是編譯器不一定會對這個函數內聯展開。編譯器也要根據實際情況進行評估,權衡展開和不展開的利弊,并最終決定要不要展開。

內聯函數并不是完美的,也有一些缺點。內聯函數會增大程序的體積。

一般而言判斷一個內聯函數是否展開,從程序員的角度主要從以下幾點出發:

函數體積小

函數體內無指針賦值、遞歸、循環語句等

調用頻繁

當我們認為一個函數體積小、而且被大量調用,應做內聯展開時,就可以使用static inline 關鍵字修飾它,但是編譯器不一定會內聯展開。如果想明確告訴編譯器一定要展開,或者不展開就可以使用 noinline 和 always_inline 對函數的屬性做一個聲明。

8.4 內聯函數為什么定義在頭文件中?

在Linux 內核中,你會看到大量的內聯函數被定義在頭文件中,而且常常使用static關鍵字修飾。

為什么定義在頭文件中呢?因為它是一個內聯函數,可以像宏一樣使用,在任何想使用內聯函數的源文件中,都不必親自在定義一遍,直接包含這個頭文件即可。

為什么還要用static 修飾呢?因為使用inline關鍵字定義的內聯函數,編譯器不一定會內聯展開,那么當一個工程中多個頭文件包含這個內聯函數的定義時,編譯時就可能報重復定義的錯誤。使用satic 關鍵字修飾,則可以限定這個函數的作用域在各自的源文件內,避免重復定義的發生。

9. 總結

本文主要介紹了 GNU C 的擴展語法 __attributr__ 關鍵字,并對其中常用的屬性聲明做了詳細的介紹:

section

packed

aligned

format

alias

weak

noinline

always_inline






審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • RAM
    RAM
    +關注

    關注

    8

    文章

    1391

    瀏覽量

    116803
  • C語言
    +關注

    關注

    180

    文章

    7630

    瀏覽量

    140400
  • 嵌入式開發
    +關注

    關注

    18

    文章

    1070

    瀏覽量

    48553
  • BSS
    BSS
    +關注

    關注

    0

    文章

    19

    瀏覽量

    12370
  • GNU
    GNU
    +關注

    關注

    0

    文章

    143

    瀏覽量

    17773

原文標題:嵌入式C代碼屬性怎么定義?

文章出處:【微信號:玩點嵌入式,微信公眾號:玩點嵌入式】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦
    熱點推薦

    嵌入式C語言的弱符號和弱引用

    總之,__attribute__ 起到了給編譯器提供上下文的作用,如果錯誤的使用 __attribute__ 指令,因為給編譯器提供了錯誤的上下文,由此引起的錯誤通常很難被發現。
    發表于 12-23 10:36 ?458次閱讀

    求助,請問一個結構體如何全部定義到 __attribute__ 區域?

    請問一個結構體如何全部定義到 __attribute__ 區域? 例如我這里涉及到一些高速計算的緩存,計劃將緩存數據存儲到 __attribute__ 區域。 三個結構體 ,每個結構體的數據大小為 4K *uint16t 這
    發表于 01-16 07:29

    __ATTRIBUTE__ 你知多少?

    GNU C 的一大特色就是__attribute__ 機制。__attribute__ 可以設置函數屬性(Func[color=rgb(68, 68, 68) !important]t
    發表于 09-05 11:12

    attribute用法section部分的資料大合集

    轉載:http://blog.sina.com.cn/s/blog_5e11a56a0100c8h5.html###1. gcc的__attribute__編譯屬性要了解Linux Kernel
    發表于 11-25 08:25

    來了解一下GNU C __attribute__機制

    mystr{int16_t a[3];} __attribute__ ((aligned));3、sectionsection控制變量或函數在編譯時的段名。在嵌入式軟件開發時用的非常多,比如有外擴
    發表于 03-03 15:49

    怎么理解RTT中#define UNUSED __attribute__((unused))這個語句呢

    'serial.c line 69Project: RTT193.mcp, Target: DebugReal, Source File: serial.c應該是不識別__attribute__((unused))這里原來應該是
    發表于 03-29 09:27

    嵌入式外中斷c語言代碼

    嵌入式外中斷c語言代碼(arm嵌入式開發實例)-嵌入式外中斷c語言
    發表于 07-30 11:29 ?5次下載
    <b class='flag-5'>嵌入式</b>外中斷<b class='flag-5'>c</b>語言<b class='flag-5'>代碼</b>

    嵌入式系統定義

    嵌入式系統定義(嵌入式開發培訓方案)-嵌入式系統定義? ? ? ? ? ? ? ? ? ? ? ??
    發表于 07-30 14:27 ?12次下載
    <b class='flag-5'>嵌入式</b>系統<b class='flag-5'>定義</b>

    __attribute__((section(x))) 使用詳解

    無論是GNU還是ARM的編譯器,都支持__attribute__所指定的編譯屬性,這里著重講解一下在KEIL環境下__attribute__中的section的使用方法。section關鍵字可以將
    發表于 11-16 18:06 ?10次下載
    __<b class='flag-5'>attribute__</b>((section(x))) 使用詳解

    C語言中的__attribute__定義之section屬性

    C語言中的 __attribute__宏之section屬性文章目錄C語言中的 __attribute__宏之section
    發表于 11-16 18:21 ?47次下載
    <b class='flag-5'>C</b>語言中的__<b class='flag-5'>attribute__</b>宏<b class='flag-5'>定義</b>之section<b class='flag-5'>屬性</b>

    __attribute__((section(“section_name“)))使用方法

    __attribute__((section("section_name")))使用方法內容待補充!!!!
    發表于 11-16 19:06 ?12次下載
    __<b class='flag-5'>attribute__</b>((section(“section_name“)))使用方法

    【STM32CubeIDE】將變量定義到指定地址

    使用Keil在使用Keil編寫程序的時候我們可以很輕松的將變量定義到指定地址uint8_t array[1024] __attribute__((at(0x20010000
    發表于 12-27 19:08 ?28次下載
    【STM32CubeIDE】將變量<b class='flag-5'>定義</b>到指定地址

    C語言中__attribute__ 關鍵字的用法

    嵌入式開發,離不開 C 語言,C語言中有很多語法會直接或間接影響你代碼的質量,下面就來講講__attribute__ 關鍵字的用法。 1.
    發表于 10-19 09:06 ?1.4w次閱讀

    rC語言__attribute__的運用

    即,在某一個結構體完成定義后,跟上一個__attribute__(xxx),這是GNU C的一個特色機制,使用__attribute__可以用來設置函數
    發表于 05-23 11:26 ?1292次閱讀

    深入探索GCC的attribute屬性

    如果經常看Linux源碼,一定會見過 attribute 屬性,他在 Linux 里面出現的很多。 attribute 是 gcc 的擴展功能,它不屬于標準C語言。 使用
    的頭像 發表于 02-13 10:05 ?332次閱讀
    主站蜘蛛池模板: 性性性性bbbbxxxx | 久久久噜久噜久久gif动图 | 婷婷五月色综合香五月 | free性日韩 | 国产精品久久久久国产精品三级 | 交在线观看网站视频 | 午夜肉伦伦影院 | 亚洲一区二区三区四区五区六区 | 91成人免费视频 | h录音 国产 在线 | 天天撸视频 | 波多野结衣一级特黄毛片 | 性过程很黄的小说男男 | 国产jzjzjz免费大全视频 | 五月婷婷六月丁香 | 天堂网视频在线 | 天天爱天天干天天 | 伊人久久大香线蕉综合7 | 亚洲午夜精品久久久久 | a色在线| 69pao强力打造免费高清 | 最新国产精品视频免费看 | 亚洲一区免费看 | 亚洲四虎 | 奇米小说 | 久久婷婷是五月综合色狠狠 | 美剧免费在线观看 | 无夜精品久久久久久 | 国产香蕉在线精彩视频 | 亚洲网色| 一级毛片女人喷潮 | 国产乱码免费卡1卡二卡3卡四 | 久久久噜久噜久久gif动图 | 色视频在线看 | 欧美成人性色 | 天堂综合网 | 欧美一级看片a免费观看 | 亚洲黄色影片 | 欧美成人精品一区二区 | 久久在精品线影院精品国产 | 亚洲成人av |