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

提高代碼逼格的利器:宏定義-從入門到放棄

開發 開發工具
一直以來,我都有這樣一種感覺:當我學習一個新領域的知識時,如果其中的某個知識點在剛開始接觸時,我感覺比較難懂、不好理解,那么以后不論我花多長時間去研究這個知識點,心里會一直認為該知識點比較難,也就是說第一印象特別的重要。
  •  一、前言
  • 二、預處理器的操作
  • 三、宏擴展
  • 四、符號:# 與 ##
  • 五、可變參數的處理
  • 六、奇思妙想的宏
  • 七、總結

一、前言

一直以來,我都有這樣一種感覺:當我學習一個新領域的知識時,如果其中的某個知識點在剛開始接觸時,我感覺比較難懂、不好理解,那么以后不論我花多長時間去研究這個知識點,心里會一直認為該知識點比較難,也就是說第一印象特別的重要。

就比如 C 語言中的宏定義,好像跟我犯沖一樣,我一直覺得宏定義是 C 語言中最難的部分,就好比有有些小伙伴一直覺得指針是 C 語言中最難的部分一樣。

宏的本質就是代碼生成器,在預處理器的支持下實現代碼的動態生成,具體的操作通過條件編譯和宏擴展來實現。我們先在心中建立這么一個基本的概念,然后通過實際的描述和代碼來深入的體會:如何駕馭宏定義。

所以,今天我們就來把宏定義所有的知識點進行匯總、深挖,希望經過這篇文章,我能夠擺脫心理的這個魔障??赐赀@篇總結文章后,我相信你也一定能夠對宏定義有一個總體、全局的把握。

二、預處理器的操作

1. 宏的生效環節:預處理

一個 C 程序在編譯的時候,從源文件開始到最后生成二進制可執行文件,一共經歷 4 個階段:

我們今天討論的內容就是在第一個環節:預處理,由預處理器來完成這個階段的工作,包括下面這 4 項工作:

  • 文件引入(#include);
  • 條件編譯(#if..#elif..#endif);
  • 宏擴展(macro expansions);
  • 行控制(line control)。

2. 條件編譯

一般情況下,C 語言文件中的每一行代碼都是要被編譯的,但是有時候出于對程序代碼優化的考慮,希望只對其中的一部分代碼進行編譯,此時就需要在程序中加上條件,讓編譯器只對滿足條件的代碼進行編譯,將不滿足條件的代碼舍棄,這就是條件編譯。

簡單的說:就是預處理器根據我們設置的條件,對代碼進行動態的處理,把有效的代碼輸出到一個中間文件,然后送給編譯器進行編譯。

條件編譯基本上在所有的項目代碼中都被使用到,例如:當你需要考慮下面的幾種情況時,就一定會使用條件編譯:

需要把程序編譯成不同平臺下的可執行程序;

同一套代碼需要運行在同一平臺上的不同功能產品上;

在程序中存在著一些測試目的的代碼,不想污染產品級的代碼,需要屏蔽掉。

這里舉 3 個例子,在代碼中經常看到的關于條件編譯:

示例1:用來區分 C 和 C++ 代碼

  1. #ifdef __cplusplus  
  2. extern "C" {  
  3. #endif  
  4.   
  5. void hello(); 
  6.   
  7. #ifdef __cplusplus  
  8. }  
  9. #endif  

這樣的代碼幾乎在每個開源庫中都可能見到,主要的目的就是 C 和 C++ 混合編程,具體來說就是:

如果使用 gcc 來編譯,那么宏 __cplusplus 將不存在,其中的 extern "C" 將會被忽略;

如果使用 g++ 來編譯,那么宏 __cplusplus 就存在,其中的 extern "C" 就發生作用,編譯出來的函數名 hello 就不會被 g++ 編譯器改寫,因此就可以被 C 代碼來調用;

示例2:用來區分不同的平臺

  1. #if defined(linux) || defined(__linux) || defined(__linux__) 
  2.     sleep(1000 * 1000); // 調用 Linux 平臺下的庫函數 
  3. #elif defined(WIN32) || defined(_WIN32) 
  4.     Sleep(1000 * 1000); // 調用 Windows 平臺下的庫函數(第一個字母是大寫) 
  5. #endif 

那么,這些 linux, __linux, __linux__, WIN32, _WIN32 是從哪里來的呢?我們可以認為是編譯目標平臺(操作系統)為我們預先準備好的。

示例3:在編寫 Windows 平臺下的動態庫時,聲明導出和導入函數

  1. #if defined(linux) || defined(__linux) || defined(__linux__) 
  2.     #define LIBA_API  
  3. #else 
  4.   #ifdef LIBA_STATIC 
  5.     #define LIBA_API 
  6.   #else 
  7.       #ifdef LIBA_API_EXPORTS 
  8.           #define LIBA_API __declspec(dllexport) 
  9.       #else 
  10.           #define LIBA_API __declspec(dllimport) 
  11.       #endif 
  12.   #endif 
  13. #endif 
  14.  
  15. // 函數聲明 
  16. LIBA_API void hello(); 

這段代碼是直接從我之前在 B 站錄制的一個小視頻里的示例拿過來的,當時主要是演示如何如何在 Linux 平臺下使用 make 和 cmake 構建工具來編譯,后來又小伙伴讓我在 Windows 平臺下也用 make 和 cmake 來構建,所以就寫了上面這段宏定義。

  • 在使用 MSVC 編譯動態庫時,需要在編譯選項(Makefle 或者 CMakeLists.txt)中定義宏 LIBA_API_EXPORTS,那么導出函數 hello 的最前面的宏 LIBA_API 就會被替換成:__declspec(dllexport),表示導出操作;
  • 在編譯應用程序的時候,使用動態庫,需要 include 動態庫的頭文件,此時在編譯選項中不需要定義宏 LIBA_API_EXPORTS,那么 hello 函數最前面的 LIBA_API 就會被替換成 __declspec(dllimport),表示導入操作;
  • 補充一點:如果使用靜態庫,編譯選項中不需要任何宏定義,那么宏 LIBA_API 就為空。

3. 平臺預定義的宏

上面已經看到了,目標平臺會為我們預先定義好一些宏,方便我們在程序中使用。除了上面的操作系統相關宏,還有另一類宏定義,在日志系統中被廣泛的使用:

  • FILE:當前源代碼文件名;
  • LINE:當前源代碼的行號;
  • FUNCTION:當前執行的函數名;
  • DATE:編譯日期;
  • TIME:編譯時間;

例如:

  1. printf("file name: %s, function name = %s, current line:%d \n", __FILE__, __FUNCTION__, __LINE__); 

三、宏擴展

所謂的宏擴展就是代碼替換,這部分內容也是我想表達的主要內容。宏擴展最大的好處有如下幾點:

  • 減少重復的代碼;
  • 完成一些通過 C 語法無法實現的功能(字符串拼接);
  • 動態定義數據類型,實現類似 C++ 中模板的功能;
  • 程序更容易理解、修改(例如:數字、字符串常亮);

我們在寫代碼的時候,所有使用宏名稱的地方,都可以理解為一個占位符。在編譯程序的預處理環節,這些宏名將會被替換成宏定義中的那些代碼段,注意:僅僅是單純的文本替換。

1. 最常見的宏

為了方便后面的描述,先來看幾個常見的宏定義:

(1) 數據類型的定義

  1. #ifndef BOOL 
  2.     typedef char BOOL; 
  3. #endif 
  4.  
  5. #ifndef TRUE 
  6.     #define TRUE 
  7. #endif 
  8.  
  9. #ifndef FALSE 
  10.     #define FALSE 
  11. #endif 

在數據類型定義中,需要注意的一點是:如果你的程序需要用不同平臺下的編譯器來編譯,那么你要去查一下所使用的編譯器對這些宏定義控制的數據類型是否已經定義了。例如:在 gcc 中沒有 BOOL 類型,但是在 MSVC 中,把 BOOL 類型定義為 int 型。

(2) 獲取最大、最小值

  1. #define MAX(a, b) (((a) > (b)) ? (a) : (b)) 
  2.  
  3. #define MIN(a, b) (((a) < (b)) ? (a) : (b)) 

(3) 計算數組中的元素個數

  1. #define ARRAY_SIZE(x)    (sizeof(x) / sizeof((x)[0])) 

(4) 位操作

  1. #define BIT_MASK(x)         (1 << (x)) 
  2. #define BIT_GET(x, y)       (((x) >> (y)) & 0x01u) 
  3. #define BIT_SET(x, y)       ((x) | (1 << (y))) 
  4. #define BIT_CLR(x, y)       ((x) & (~(1 << (y)))) 
  5. #define BIT_INVERT(x, y)    ((x) ^ (1 << (y))) 

2. 與函數的區別

從上面這幾個宏來看,所有的這些操作都可以通過函數來實現,那么他們各有什么優缺點呢?

通過函數來實現:

  • 形參的類型需要確定,調用時對參數進行檢查;
  • 調用函數時需要額外的開銷:操作函數棧中的形參、返回值等;

通過宏來實現:

  • 不需要檢查參數,更靈活的傳參;
  • 直接對宏進行代碼擴展,執行時不需要函數調用;
  • 如果同一個宏在多處調用,會增加代碼體積;

還是舉一個例子來說明比較好,就拿上面的比較大小來說吧:

(1) 使用宏來實現

  1. #define MAX(a, b)    (((a) > (b)) ? (a) : (b)) 
  2.  
  3. int main() 
  4.     printf("max: %d \n"MAX(1, 2)); 

(2) 使用函數來實現

  1. int max(int a, int b) 
  2.     if (a > b) 
  3.         return a; 
  4.     return b; 
  5.  
  6. int main() 
  7.     printf("max: %d \n"max(1, 2)); 

除了函數調用的開銷,其它看起來沒有差別。這里比較的是 2 個整型數據,那么如果還需要比較 2 個浮點型數據呢?

  • 使用宏來調用:MAX(1.1, 2.2);一切 OK;
  • 使用函數調用:max(1.1, 2.2); 編譯報錯:類型不匹配。

此時,使用宏來實現的優勢就體現出來了:因為宏中沒有類型的概念,調用者傳入任何數據類型都可以,然后在后面的比較操作中,大于或小于操作都是利用了 C 語言本身的語法來執行。

如果使用函數來實現,那么就必須再定義一個用來操作浮點型的函數,以后還有可能比較:char 型、long 型數據等等。

在 C++ 中,這樣的操作可以通過參數模板來實現,所謂的模板也是一種代碼動態生成機制。當定義了一個函數模板后,根據調用者的實參,來動態產生多個函數。例如定義下面這個函數模板:

  1. template<typename T> T max(T a, T b){ 
  2.     if (a > b)  
  3.         return a; 
  4.     return b; 
  5.  
  6. max(1, 2);     // 實參是整型 
  7. max(1.1, 2,2); // 實參是浮點型 

當編譯器看到 max(1, 2) 時,就會動態生成一個函數 int max(int a, int b) { ... };

當編譯器看到 max(1.1, 2.2) 時,又會動態生成另一個函數 float max(float a, float b) { ... }。

所以,從代碼的動態生成角度看,宏定義和 C++ 中的模板參數有點神似,只不過宏定義僅僅是代碼擴展而已。

下面這個例子也比較不錯,利用宏的類型無關,來動態生成結構體:

  1. #define VEC(T)          \ 
  2.     struct vector_##T { \ 
  3.         T *data;       \ 
  4.         size_t size;    \ 
  5.     }; 
  6.  
  7. int main() 
  8.     VEC(int)   vec_1 = { .data = NULL, .size = 0 }; 
  9.     VEC(float) vec_2 = { .data = NULL, .size = 0 }; 

這個例子中用到了 ##,下面會解釋這個知識點。在前面的例子中,宏的參數傳遞的都是一些變量,而這里傳遞的宏參數是數據類型,通過宏的類型無關性,達到了“動態”創建結構體的目的:

  1. struct vector_int { 
  2.     int *data; 
  3.     size_t size
  4.  
  5. struct vector_float { 
  6.     float *data; 
  7.     size_t size

這里有一個陷阱需要注意:傳遞的數據類型中不能有空格,如果這樣使用:VEC(long long),那替換之后得到:

  1. struct vector_long long {  // 語法錯誤 
  2.     long long *data; 
  3.     size_t size

四、符號:# 與 ##

這兩個符號在編程中的作用也是非常巧妙,夸張的說一句:在任何框架性代碼中,都能見到它們的身影!作用如下:

  • #:把參數轉換成字符串;
  • ##:連接參數。

1. #: 字符串化

直接看最簡單的例子:

  1. #define STR(x) #x 
  2. printf("string of 123: %s \n", STR(123)); 

傳入的是一個數字 123,輸出的結果是字符串 “123”,這就是字符串化。

2. ##:參數連接

把宏中的參數按照字符進行拼接,從而得到一個新的標識符,例如:

  1. #define MAKE_VAR(namenoname##no 
  2.  
  3. int main(void) 
  4.     int MAKE_VAR(a, 1) = 1;  
  5.     int MAKE_VAR(b, 2) = 2;  
  6.  
  7.     printf("a1 = %d \n", a1); 
  8.     printf("b2 = %d \n", b2); 
  9.     return 0; 

當調用宏 MAKE_VAR(a, 1) 后,符號 ## 把兩側的 name 和 no 首先替換為 a 和 1,然后連接得到 a1。然后在調用語句中前面的 int 數據類型就說明了 a1 是一個整型數據,最后初始化為 1。

五、可變參數的處理

1. 參數名的定義和使用

宏定義的參數個數可以是不確定的,就像調用 printf 打印函數一樣,在定義的時候,可以使用三個點(...)來表示可變參數,也可以在三個點的前面加上可變參數的名稱。

如果使用三個點(...)來接收可變參數,那么在使用的時候就需要使用 VA_ARGS 來表示可變參數,如下:

  1. #define debug1(...)      printf(__VA_ARGS__) 
  2.  
  3. debug1("this is debug1: %d \n", 1); 

如果在三個點(...)的前面加上了一個參數名,那么在使用時就一定要使用這個參數名,而不能使用 VA_ARGS 來表示可變參數,如下:

  1. #define debug2(args...)  printf(args) 
  2.  
  3. debug1("this is debug2: %d \n", 2); 

2. 可變參數個數為零的處理

看一下這個宏:

  1. #define debug3(format, ...)      printf(format, __VA_ARGS__) 
  2.  
  3. debug3("this is debug4: %d \n", 4); 

編譯、執行都沒有問題。但是如果這樣來使用宏:

  1. debug3("hello \n"); 

編譯的時候,會出現錯誤: error: expected expression before ‘)’ token。為什么呢?

看一下宏擴展之后的代碼(__VA_ARGS__為空):

  1. printf("hello \n",); 

看出問題了吧?在格式化字符串的后面多了一個逗號!為了解決問題,預處理器給我們提供了一個方法:通過 ## 符號把這個多余的逗號給自動刪掉。于是宏定義改成下面這樣就沒有問題了。

  1. #define debug3(format, ...)     printf(format, ##__VA_ARGS__) 

類似的,如果自己定義了可變參數的名字,也在前面加上 ##,如下:

  1. #define debug4(format, args...)  printf(format, ##args) 

六、奇思妙想的宏

宏擴展的本質就是文本替換,但是一旦加上可變參數(__VA_ARGS__)和 ## 的連接功能,就能夠變化出無窮的想象力。

我一直堅信,模仿是成為高手的第一步,只有見多識廣、多看、多學習別人是怎么來使用宏的,然后拿來為己所用,按照“先僵化-再優化-最后固化”這個步驟來訓練,總有一天你也能成為高手。

這里我們就來看幾個利用宏定義的巧妙實現。

1. 日志功能

在代碼中添加日志功能,幾乎是每個產品的標配了,一般見到最普遍的是下面這樣的用法:

  1. #ifdef DEBUG 
  2.     #define LOG(...) printf(__VA_ARGS__) 
  3. #else 
  4.     #define LOG(...)  
  5. #endif 
  6.  
  7. int main() 
  8.     LOG("name = %s, age = %d \n""zhangsan", 20); 
  9.     return 0; 

在編譯的時候,如果需要輸出日志功能就傳入宏定義 DEBUG,這樣就能打印輸出調試信息,當然實際的產品中需要寫入到文件中。如果不需要打印語句,通過把打印日志信息那條語句定義為空語句來達到目的。

換個思路,我們還可以通過條件判斷語句來控制打印信息,如下:

  1. #ifdef DEBUG 
  2.     #define debug if(1) 
  3. #else 
  4.      #define debug if(0) 
  5. #endif 
  6.  
  7. int main() 
  8.     debug { 
  9.         printf("name = %s, age = %d \n""zhangsan", 20); 
  10.     } 
  11.     return 0; 

這樣控制日志信息的看到的不多,但是也能達到目的,放在這里只是給大家開闊一下思路。

2. 利用宏來迭代每個參數

  1. #define first(x, ...) #x 
  2. #define rest(x, ...)  #__VA_ARGS__ 
  3.  
  4. #define destructive(...)                              \ 
  5.     do {                                              \ 
  6.         printf("first is: %s\n"first(__VA_ARGS__)); \ 
  7.         printf("rest are: %s\n", rest(__VA_ARGS__));  \ 
  8.     } while (0) 
  9.  
  10. int main(void) 
  11.     destructive(1, 2, 3); 
  12.     return 0; 

主要的思想就是:每次把可變參數 VA_ARGS 中的第一個參數給分離出來,然后把后面的參數再遞歸處理,這樣就可以分離出每一個參數了。我記得侯杰老師在 C++ 的視屏中,利用可變參數模板這個語法,也實現了類似的功能。

剛才在有道筆記中居然找到了侯杰老師演示的代碼,熟悉 C++ 的小伙伴可以研究下下面這段代碼:

  1. // 遞歸的最后一次調用 
  2. void myprint() 
  3.  
  4. template <typename T, typename... Types> 
  5. void myprint(const T &first, const Types&... args) 
  6.     std::cout << first << std::endl; 
  7.     std::cout << "remain args size = " << sizeof...(args) << std::endl; 
  8.     
  9.     // 把其他參數遞歸調用 
  10.   myprint(args...); 
  11.  
  12. int main() 
  13.     myprint("aaa", 7.5, 100); 
  14.     return 0; 

3. 動態的調用不同的函數

  1. // 普通的枚舉類型 
  2. enum { 
  3.   ERR_One, 
  4.   ERR_Two, 
  5.   ERR_Three 
  6. }; 
  7.  
  8. // 利用 ## 的拼接功能,動態產生 case 中的比較值,以及函數名。 
  9. #define TEST(no) \ 
  10.     case ERR_##no: \ 
  11.       Func_##no(); \ 
  12.       break; 
  13.  
  14. void Func_One() 
  15.     printf("this is Func_One \n"); 
  16.  
  17. void Func_Two() 
  18.     printf("this is Func_Two \n"); 
  19.  
  20. void Func_Three() 
  21.     printf("this is Func_Three \n"); 
  22.  
  23. int main() 
  24.     int c = ERR_Two; 
  25.     switch (c) { 
  26.         TEST(One); 
  27.         TEST(Two); 
  28.         TEST(Three); 
  29.     }; 
  30.  
  31.     return 0; 

在這個例子中,核心在于 TEST 宏定義,通過 ## 拼接功能,構造出 case 分支的比較目標,然后動態拼接得到對應的函數,最后調用這個函數。

4. 動態創建錯誤編碼與對應的錯誤字符串

這也是一個非常巧妙的例子,利用了 #(字符串化) 和 ##(拼接) 這 2 個功能來動態生成錯誤編碼碼和相應的錯誤字符串:

  1. #define MY_ERRORS     \ 
  2.     E(TOO_SMALL)      \ 
  3.     E(TOO_BIG)        \ 
  4.     E(INVALID_VARS) 
  5.  
  6. #define E(e) Error_## e, 
  7. typedef enum { 
  8.     MY_ERRORS 
  9. } MyEnums; 
  10. #undef E 
  11.  
  12. #define E(e) #e, 
  13. const char *ErrorStrings[] = { 
  14.     MY_ERRORS 
  15. }; 
  16. #undef E 
  17.  
  18. int main() 
  19.     printf("%d - %s \n", Error_TOO_SMALL, ErrorStrings[0]); 
  20.     printf("%d - %s \n", Error_TOO_BIG, ErrorStrings[1]); 
  21.     printf("%d - %s \n", Error_INVALID_VARS, ErrorStrings[2]); 
  22.  
  23.     return 0; 

我們把宏展開之后,得到一個枚舉類型和一個字符串常量數組:

  1. typedef enum { 
  2.     Error_TOO_SMALL, 
  3.     Error_TOO_BIG, 
  4.     Error_INVALID_VARS, 
  5. } MyEnums; 
  6.  
  7. const char *ErrorStrings[] = { 
  8.     "TOO_SMALL"
  9.     "TOO_BIG"
  10.     "INVALID_VARS"
  11. }; 

宏擴展之后的代碼是不是很簡單啊。編譯、執行結果如下:

  1. 0 - TOO_SMALL  
  2. 1 - TOO_BIG  
  3. 2 - INVALID_VARS 

七、總結

有些人對宏愛之要死,多到濫用的程度;而有些人對宏恨之入骨,甚至用上了邪惡(evil)這個詞!其實宏對于 C 來說,就像菜刀對于廚師和歹徒一樣:用的好,可以讓代碼結構簡潔、后期維護特別方便;用的不好,就會引入晦澀的語法、難以調試的 Bug。

對于我們開發人員來說,只要在程序的執行效率、代碼的可維護性上做好平衡就可以了。

本文轉載自微信公眾號「 IOT物聯網小鎮」,可以通過以下二維碼關注。轉載本文請聯系 IOT物聯網小鎮公眾號。

 

責任編輯:武曉燕 來源: IOT物聯網小鎮
相關推薦

2019-07-02 14:17:18

API網關網關流量

2017-03-25 20:30:15

2025-04-22 02:00:00

芯片晶圓光刻機

2017-12-25 11:15:06

JavaArray數組

2020-07-07 10:50:19

Python丄則表達文本

2022-01-17 08:52:32

CPUCPU工具顯卡

2020-04-10 15:05:09

深度學習人工智能蒸餾

2018-01-26 14:35:16

程序員入門經歷

2016-08-03 16:01:47

GitLinux開源

2021-11-08 07:11:49

決策樹數據分類器

2022-03-28 11:00:34

JVMJava對象

2022-04-19 11:25:31

JVMZGC垃圾收集器

2019-06-23 15:21:42

Google谷歌平板

2021-05-11 11:08:37

電腦病毒軟件

2021-08-02 06:49:46

Flutter Router安全

2019-09-16 16:16:24

DIY機箱CPU

2024-01-31 07:47:06

C++預定義宏編程

2025-08-12 08:45:11

2022-04-21 08:20:33

CPU換蓋CPU

2021-10-25 05:54:59

SSD固態硬盤存儲
點贊
收藏

51CTO技術棧公眾號

92裸体在线视频网站| 久久精品水蜜桃av综合天堂| 欧美麻豆久久久久久中文| 性色av浪潮av| 香蕉伊大人中文在线观看| 久久久精品综合| 亚洲a∨日韩av高清在线观看| 婷婷伊人五月天| 自拍一区在线观看| 最新热久久免费视频| 国产欧美亚洲日本| 在线观看av大片| 天堂日韩电影| 在线91免费看| 欧美日本视频在线观看| 欧美性猛交xxx乱大交3蜜桃| 成人少妇影院yyyy| 国产精品一区久久| 日韩精品1区2区| 中文字幕av亚洲精品一部二部| 日韩精品在线私人| 三级网站免费看| 午夜日韩成人影院| 亚洲成在人线免费| 9l视频自拍9l视频自拍| 91麻豆成人精品国产| 最新成人av网站| 久久av资源网站| 无码少妇精品一区二区免费动态| 9l视频自拍九色9l视频成人| 在线播放国产精品二区一二区四区 | 国模杨依粉嫩蝴蝶150p| 伊人222成人综合网| 精品午夜久久福利影院| zzijzzij亚洲日本成熟少妇| aaaaa一级片| 91九色鹿精品国产综合久久香蕉| 欧美视频完全免费看| 日韩在线第一区| 深爱五月激情五月| 成人一级视频在线观看| 91久久精品在线| 亚洲视频一区二区三区四区| 国产精品一区毛片| 亚洲色图国产精品| 欧美一区二区免费在线观看| 亚洲精品福利| 日韩精品一区二区三区中文不卡| 国内av一区二区| 成人综合日日夜夜| 欧美夫妻性生活| xxxx在线免费观看| 台湾天天综合人成在线| 欧美视频一区二区三区四区| 五月天激情视频在线观看| 免费成人动漫| 亚洲欧美国产三级| 欧美与动交zoz0z| 在线播放免费av| 夜夜嗨av一区二区三区中文字幕 | 大桥未久恸哭の女教师| 亚洲国产欧美在线观看| 亚洲精品一线二线三线无人区| 少妇愉情理伦片bd| 国产精品毛片视频| 日韩av最新在线观看| 免费a级黄色片| 国产真实有声精品录音| 中文字幕av一区中文字幕天堂 | 极品美女扒开粉嫩小泬| 午夜在线播放| 亚洲欧美一区二区三区孕妇| 成人在线免费高清视频| 免费污视频在线| 午夜激情一区二区三区| 精品视频一区二区在线| japanese23hdxxxx日韩| 欧美日韩和欧美的一区二区| 中文字幕一区二区在线观看视频| 日韩激情电影免费看| 日韩欧中文字幕| 亚洲美女性囗交| 9l视频自拍蝌蚪9l视频成人| 亚洲欧美另类在线观看| 国产精品一区二区亚洲| 国产精品二区影院| 久久亚洲私人国产精品va| 免费日韩在线视频| 亚洲自拍另类| 欧美激情一区二区三级高清视频| 精品欧美一区二区三区免费观看 | 国产精品久久久久一区二区三区厕所 | 亚洲免费精品| 国产精品久久久久久av| 日产精品久久久久久久| 日韩精品国产欧美| 欧美亚洲成人免费| 伊人网av在线| 麻豆精品在线观看| 电影午夜精品一区二区三区| 国模吧精品人体gogo| 亚洲免费色视频| 韩国日本在线视频| 国产精品亚洲一区二区在线观看| 亚洲精品mp4| 精品人妻二区中文字幕| 九九视频精品全部免费播放| 久久国产精品影视| 欧美一级淫片免费视频黄| 国产高清在线精品| 亚洲国产欧美日韩| 中文一区一区三区高中清不卡免费 | 日韩中文理论片| 欧美偷拍一区二区三区| 欧美成人中文| 国产精品视频yy9099| 亚洲色图另类小说| 亚洲色图清纯唯美| 久久国产乱子伦免费精品| 99精品在免费线中文字幕网站一区| 亚洲最新av在线| 六月丁香在线视频| 国产成人99久久亚洲综合精品| 亚洲7777| 免费大片在线观看www| 欧美性xxxx极品hd满灌| xxxxwww一片| 伊人青青综合网| 成人福利视频网| av中文资源在线| 色94色欧美sute亚洲线路一久| 动漫美女无遮挡免费| 中文字幕免费精品| 91久久国产精品| 色的视频在线免费看| 欧美亚洲综合一区| 90岁老太婆乱淫| 午夜综合激情| 免费国产在线精品一区二区三区| 波多野在线观看| 精品欧美一区二区在线观看 | 午夜精品一区二区三区三上悠亚| 视频区 图片区 小说区| 99精品视频精品精品视频| 国产精品美女999| jzzjzzjzz亚洲成熟少妇| 在线观看免费亚洲| 久久视频精品在线观看| 性久久久久久| 欧美激情一区二区三区在线视频| 麻豆国产在线| 日韩二区三区在线| 国产又大又黄又粗| 久久蜜桃一区二区| 人妻无码视频一区二区三区| 亚洲精品动态| 日韩免费在线免费观看| 国产美女性感在线观看懂色av| 日本福利一区二区| 国产无遮挡在线观看| 美女视频黄频大全不卡视频在线播放| 亚洲视频小说| 高清久久一区| 久久久久久91| 婷婷国产在线| 亚洲欧洲国产日韩| 交换做爰国语对白| 亚洲三级毛片| 日韩wuma| 国产精品欧美一区二区三区不卡 | 看片的网站亚洲| 欧美性受黑人性爽| 51社区在线成人免费视频| 国产69精品久久久久久| 成年人免费在线视频| 91精品国产全国免费观看| 水蜜桃av无码| 久久久久久穴| 中文字幕一区二区中文字幕| 97视频一区| 欧洲成人在线视频| 蜜桃视频在线观看www社区| 日韩精品一区二区三区swag| 国产免费av一区二区| 国产精品视频一二三| 尤物网站在线看| 宅男噜噜噜66一区二区| 亚洲天堂电影网| 99久热这里只有精品视频免费观看| 91禁国产网站| 日本a级在线| 日韩精品久久久久| 91午夜交换视频| 午夜精品久久久久久久99水蜜桃 | 国产亚洲电影| 91精品入口蜜桃| 国产日韩电影| 欧美成人黄色小视频| 深夜视频在线免费| 91精品国产91热久久久做人人 | 亚洲午夜久久久久久久国产| 国产高清成人在线| 国内自拍视频一区| 亚洲视频福利| 在线视频不卡国产| 亚洲人和日本人hd| 成人18视频| 91精品国产66| 国产亚洲aⅴaaaaaa毛片| 性少妇videosexfreexxx片| 一本色道久久综合亚洲91| 九九免费精品视频| 国产精品网站一区| 国产麻豆天美果冻无码视频| 国产一区二区剧情av在线| 欧美一级片中文字幕| 一区久久精品| 久久久久久欧美精品色一二三四| 亚洲我射av| 国产精品成人va在线观看| a级片免费在线观看| 久久综合久久八八| 91视频在线观看| 亚洲午夜激情免费视频| 亚洲 另类 春色 国产| 精品乱人伦小说| 国产精品无码久久久久成人app| 色哦色哦哦色天天综合| www.中文字幕在线观看| 亚洲综合色噜噜狠狠| 亚洲国产123| 中文字幕一区二区三区四区| 日韩久久久久久久久久久| 日韩高清电影一区| 国产日韩一区二区在线观看| 国产欧美成人| 免费看又黄又无码的网站| 亚洲国产99| 成人午夜视频在线观看免费| 欧美私人啪啪vps| 日本大胆人体视频| 欧美日本精品| 亚洲中文字幕无码一区二区三区 | 免费特级黄色片| 国语自产精品视频在线看8查询8| 国产精品av免费观看| 一本一道久久综合狠狠老| 亚洲区成人777777精品| 欧美日韩一区二区国产| 久久这里只有精品8| 要久久电视剧全集免费| 久久99九九| 日韩大胆成人| 美女主播视频一区| 在线日韩网站| 亚洲国产欧美一区二区三区不卡| 成人国产精品一级毛片视频| 999国产视频| 日韩一区二区三区精品视频第3页| 91传媒视频在线观看| 综合欧美亚洲| 久久久久天天天天| 欧美日韩一区二区综合| 亚洲三区四区| 国自产拍偷拍福利精品免费一| 久操网在线观看| 欧美专区一区二区三区| 91av俱乐部| 国产一区二区三区久久悠悠色av | 91蜜桃在线免费视频| 五月花丁香婷婷| 国产一区不卡视频| 人妻体内射精一区二区三区| 久久夜色精品国产噜噜av| 黄大色黄女片18免费| 91视视频在线直接观看在线看网页在线看 | 久久精品美女视频| 日韩欧美在线免费| 中文天堂在线视频| 日韩亚洲电影在线| 日本福利片在线| 久久精品国产成人| 九九精品调教| 国产精品久久久久久久午夜| 久久一级大片| 日本欧洲国产一区二区| 综合激情在线| 亚洲乱码国产一区三区| 国产在线观看一区二区| 一区二区三区少妇| 亚洲视频一二区| 国产精品成人久久| 欧美亚洲动漫另类| 欧美一级特黄aaaaaa大片在线观看| 欧美久久久久久久久久| 污视频网站免费观看| 中文字幕亚洲一区二区三区| 国产盗摄在线视频网站| 国产精品国产亚洲伊人久久 | 日韩成人av在线播放| 在线观看av的网站| 456国产精品| 日韩综合一区二区三区| 色之综合天天综合色天天棕色| 亚洲视频综合| 国产精品久久久久久9999| 久久免费午夜影院| 国产精品不卡av| 91精品久久久久久久久99蜜臂| 日韩精品视频无播放器在线看| 久久久国产精品免费| 激情开心成人网| 黑人巨大精品欧美一区二区小视频| 99热在线成人| 黄色三级视频片| 久久一区二区三区四区| 日本妇女毛茸茸| 欧美日韩精品三区| 黄色电影免费在线看| 午夜精品一区二区三区在线| 国产一区二区三区免费在线 | 一区在线免费观看| 国产免费中文字幕| 国产精品视频观看| 欧美另类高清videos的特点| 国产午夜精品久久久| 91视频欧美| 国产私拍一区| 亚洲另类视频| 制服丝袜第一页在线观看| 亚洲综合在线观看视频| 国产福利视频导航| 久久综合电影一区| 美女精品视频在线| 在线观看av的网址| 国产精品夜夜爽| 欧美成人精品一区二区免费看片| 91精品国产入口| 丝袜在线观看| 97高清免费视频| 超碰成人免费| 国产精品久久久久9999爆乳| 国产99一区视频免费| 欧美精品一区二区成人| 日韩三级免费观看| 国产精品国精产品一二| 国产一区二区高清不卡| 国户精品久久久久久久久久久不卡| 亚洲熟女乱综合一区二区| 一区二区在线观看视频| 亚洲AV无码国产精品午夜字幕| 欧美激情精品久久久| 伊人久久高清| 午夜精品短视频| 久久国产精品露脸对白| 91视频青青草| 日韩视频永久免费| a√中文在线观看| 久久久久久久久久久久久久一区 | 9.1在线观看免费| 午夜视频一区在线观看| 日本v片在线免费观看| 国产精品久久精品| 亚洲欧美综合久久久| 男人的天堂免费| 午夜成人免费视频| 国产高清一区在线观看| 91免费版网站入口| 亚洲激情一区| xxxx日本黄色| 91麻豆精品国产自产在线观看一区| 羞羞网站在线免费观看| 国产一级二级三级精品| 久久蜜桃精品| 日韩av手机在线免费观看| 精品久久久久久久久久久久久久久| 嗯~啊~轻一点视频日本在线观看| 欧美三级电影在线播放| 久久 天天综合| 丰满少妇乱子伦精品看片| 伊人激情综合网| 日本综合精品一区| 国产aaa一级片| 亚洲天堂免费看| 亚洲欧美日韩成人在线| 国产精品嫩草视频| 国自产拍偷拍福利精品免费一| 色一情一交一乱一区二区三区| 91麻豆精品久久久久蜜臀| 在线日韩影院| 日韩精品手机在线观看| 久久久99精品免费观看| 亚洲第一色视频| 国产精品久久久久一区二区| 黄色av成人| sm捆绑调教视频| 亚洲精品永久免费| 亚洲1区在线观看| 亚洲欧美自拍另类日韩| 国产日韩欧美一区二区三区乱码 |