亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

C++ 代碼優化

2019-11-17 05:20:20
字體:
來源:轉載
供稿:網友

  談到優化,很多人都會直接想到匯編。難道優化只能在匯編層次嗎?當然不是,C++層次一樣可以作代碼優化,其中有些經常是意想不到的。在C++層次進行優化,比在匯編層次優化具有更好的移植性,應該是優化中的首選做法。

  確定浮點型變量和表達式是 float 型

  為了讓編譯器產生更好的代碼(比如說產生3DNow! 或SSE指令的代碼),必須確定浮點型變量和表達式是 float 型的。要非凡注重的是,以 ";F"; 或 ";f"; 為后綴(比如:3.14f)的浮點常量才是 float 型,否則默認是 double 型。為了避免 float 型參數自動轉化為 double,請在函數聲明時使用 float。

  使用32位的數據類型

  編譯器有很多種,但它們都包含的典型的32位類型是:int,signed,signed int,unsigned,unsigned int,long,signed long,long int,signed long int,unsigned long,unsigned long int。盡量使用32位的數據類型,因為它們比16位的數據甚至8位的數據更有效率。

  明智使用有符號整型變量

  在很多情況下,你需要考慮整型變量是有符號還是無符號類型的。比如,保存一個人的體重數據時不可能出現負數,所以不需要使用有符號類型。但是,假如是要保存溫度數據,就必須使用到有符號的變量。

  在許多地方,考慮是否使用有符號的變量是必要的。在一些情況下,有符號的運算比較快;但在一些情況下卻相反。

  比如:整型到浮點轉化時,使用大于16位的有符號整型比較快。因為x86構架中提供了從有符號整型轉化到浮點型的指令,但沒有提供從無符號整型轉化到浮點的指令??纯淳幾g器產生的匯編代碼:

  不好的代碼:

編譯前 編譯后

double x; mov [foo + 4], 0
unsigned int i; mov eax, i
x = i; mov [foo], eax
flid qWord ptr [foo]
fstp qword ptr [x]
  上面的代碼比較慢。不僅因為指令數目比較多,而且由于指令不能配對造成的FLID指令被延遲執行。最好用以下代碼代替:
推薦的代碼:

編譯前 編譯后

double x; fild dword ptr [i]
int i; fstp qword ptr [x]
x = i;
  在整數運算中計算商和余數時,使用無符號類型比較快。以下這段典型的代碼是編譯器產生的32位整型數除以4的代碼:

  不好的代碼 推薦的代碼

編譯前 編譯后

int i; mov eax, i
i = i / 4; cdq
and edx, 3
add eax, edx
sar eax, 2
mov i, eax
編譯前 編譯后

unsigned int i; shr i, 2
i = i / 4;
  總結:
  無符號類型用于:
  除法和余數
  循環計數
  數組下標
  有符號類型用于:
  整型到浮點的轉化
  while VS. for

  在編程中,我們經常需要用到無限循環,常用的兩種方法是while (1) 和 for (;;)。這兩種方法效果完全一樣,但那一種更好呢?然我們看看它們編譯后的代碼:

編譯前 編譯后

while (1); mov eax,1
test eax,eax
je foo+23h
jmp foo+18h
編譯前 編譯后

for (;;); jmp foo+23h
  一目了然,for (;;)指令少,不占用寄存器,而且沒有判定跳轉,比while (1)好?! ∈褂脭到M型代替指針型

  使用指針會使編譯器很難優化它。因為缺乏有效的指針代碼優化的方法,編譯器總是假設指針可以訪問內存的任意地方,包括分配給其他變量的儲存空間。所以為了編譯器產生優化得更好的代碼,要避免在不必要的地方使用指針。一個典型的例子是訪問存放在數組中的數據。C++ 答應使用操作符 [] 或指針來訪問數組,使用數組型代碼會讓優化器減少產生不安全代碼的可能性。比如,x[0] 和x[2] 不可能是同一個內存地址,但 *p 和 *q 可能。強烈建議使用數組型,因為這樣可能會有意料之外的性能提升。

不好的代碼 推薦的代碼

typedef strUCt
{
  float x,y,z,w;
} VERTEX;
typedef struct
{
  float m[4][4];
} MATRIX;
void XForm(float* res, const float* v, const float* m, int nNumVerts)
{
  float dp;
  int i;
   const VERTEX* vv = (VERTEX *)v;
   for (i = 0; i <; nNumVerts; i++)
  {
    dp = vv->;x * *m ++;
    dp += vv->;y * *m ++;
    dp += vv->;z * *m ++;
    dp += vv->;w * *m ++;
    *res ++ = dp;      // 寫入轉換了的 x
    dp = vv->;x * *m ++;
    dp += vv->;y * *m ++;
    dp += vv->;z * *m ++;
    dp += vv->;w * *m ++;
    *res ++ = dp;     // 寫入轉換了的 y
    dp = vv->;x * *m ++;
    dp += vv->;y * *m ++;
    dp += vv->;z * *m ++;
    dp += vv->;w * *m ++;
    *res ++ = dp;    // 寫入轉換了的 z
    dp = vv->;x * *m ++;
    dp += vv->;y * *m ++;
    dp += vv->;z * *m ++;
    dp += vv->;w * *m ++;
    *res ++ = dp;    // 寫入轉換了的 w
    vv ++;        // 下一個矢量
    m -= 16;
  }
}
typedef struct
{
  float x,y,z,w;
} VERTEX;
typedef struct
{
  float m[4][4];
} MATRIX;
void XForm (float* res, const float* v, const float* m, int nNumVerts)
{
  int i;
  const VERTEX* vv = (VERTEX*)v;
  const MATRIX* mm = (MATRIX*)m;
  VERTEX* rr = (VERTEX*)res;
  for (i = 0; i <; nNumVerts; i++)
  {
    rr->;x = vv->;x * mm->;m[0][0] + vv->;y * mm->;m[0][1]
        + vv->;z * mm->;m[0][2] + vv->;w * mm->;m[0][3];
    rr->;y = vv->;x * mm->;m[1][0] + vv->;y * mm->;m[1][1]
        + vv->;z * mm->;m[1][2] + vv->;w * mm->;m[1][3];
    rr->;z = vv->;x * mm->;m[2][0] + vv->;y * mm->;m[2][1]
        + vv->;z * mm->;m[2][2] + vv->;w * mm->;m[2][3];
    rr->;w = vv->;x * mm->;m[3][0] + vv->;y * mm->;m[3][1]
        + vv->;z * mm->;m[3][2] + vv->;w * mm->;m[3][3];
  }
}
  注重: 源代碼的轉化是與編譯器的代碼發生器相結合的。從源代碼層次很難控制產生的機器碼。依靠編譯器和非凡的源代碼,有可能指針型代碼編譯成的機器碼比同等條件下的數組型代碼運行速度更快。明智的做法是在源代碼轉化后檢查性能是否真正提高了,再選擇使用指針型還是數組型。
  充分分解小的循環

  要充分利用CPU的指令緩存,就要充分分解小的循環。非凡是當循環體本身很小的時候,分解循環可以提高性能。BTW:很多編譯器并不能自動分解循環。

不好的代碼 推薦的代碼

// 3D轉化:把矢量 V 和 4x4 矩陣 M 相乘
for (i = 0; i <; 4; i ++)
{
  r[i] = 0;
  for (j = 0; j <; 4; j ++)
  {
    r[i] += M[j][i]*V[j];
  }
}
r[0] = M[0][0]*V[0] + M[1][0]*V[1] + M[2][0]*V[2] + M[3][0]*V[3];
r[1] = M[0][1]*V[0] + M[1][1]*V[1] + M[2][1]*V[2] + M[3][1]*V[3];
r[2] = M[0][2]*V[0] + M[1][2]*V[1] + M[2][2]*V[2] + M[3][2]*V[3];
r[3] = M[0][3]*V[0] + M[1][3]*V[1] + M[2][3]*V[2] + M[3][3]*v[3];
  避免沒有必要的讀寫依靠

  當數據保存到內存時存在讀寫依靠,即數據必須在正確寫入后才能再次讀取。雖然AMD Athlon等CPU有加速讀寫依靠延遲的硬件,答應在要保存的數據被寫入內存前讀取出來,但是,假如避免了讀寫依靠并把數據保存在內部寄存器中,速度會更快。在一段很長的又互相依靠的代碼鏈中,避免讀寫依靠顯得尤其重要。假如讀寫依靠發生在操作數組時,許多編譯器不能自動優化代碼以避免讀寫依靠。所以推薦程序員手動去消除讀寫依靠,舉例來說,引進一個可以保存在寄存器中的臨時變量。這樣可以有很大的性能提升。下面一段代碼是一個例子:

  不好的代碼 推薦的代碼

float x[VECLEN], y[VECLEN], z[VECLEN];
......
for (unsigned int k = 1; k <; VECLEN; k ++)
{
  x[k] = x[k-1] + y[k];
}
for (k = 1; k <; VECLEN; k++)
{
  x[k] = z[k] * (y[k] - x[k-1]);
}
float x[VECLEN], y[VECLEN], z[VECLEN];
......
float t(x[0]);
for (unsigned int k = 1; k <; VECLEN; k ++)
{
  t = t + y[k];
  x[k] = t;
}
t = x[0];
for (k = 1; k <; VECLEN; k ++)
{
  t = z[k] * (y[k] - t);
  x[k] = t;
}
  Switch 的用法

  Switch 可能轉化成多種不同算法的代碼。其中最常見的是跳轉表和比較鏈/樹。推薦對case的值依照發生的可能性進行排序,把最有可能的放在第一個,當switch用比較鏈的方式轉化時,這樣可以提高性能。此外,在case中推薦使用小的連續的整數,因為在這種情況下,所有的編譯器都可以把switch 轉化成跳轉表。

不好的代碼 推薦的代碼

int days_in_month, short_months, normal_months, long_months;
......

switch (days_in_month)
{
  case 28:
  case 29:
    short_months ++;
    break;
  case 30:
    normal_months ++;
    break;
  case 31:
    long_months ++;
    break;
  default:
    cout <;<; ";month has fewer than 28 or more than 31 days"; <;<; endl;
    break;
}
int days_in_month, short_months, normal_months, long_months;
......

switch (days_in_month)
{
  case 31:
    long_months ++;
    break;
  case 30:
    normal_months ++;
    break;
  case 28:
  case 29:
    short_months ++;
    break;
  default:
    cout <;<; ";month has fewer than 28 or more than 31 days"; <;<; endl;
    break;
}
  所有函數都應該有原型定義

  一般來說,所有函數都應該有原型定義。原型定義可以傳達給編譯器更多的可能用于優化的信息。

  盡可能使用常量(const)

  盡可能使用常量(const)。C++ 標準規定,假如一個const聲明的對象的地址不被獲取,答應編譯器不對它分配儲存空間。這樣可以使代碼更有效率,而且可以生成更好的代碼?! √嵘h的性能

  要提升循環的性能,減少多余的常量計算非常有用(比如,不隨循環變化的計算)。

  不好的代碼(在for()中包含不變的if()) 推薦的代碼

for( i ... )
{
  if( CONSTANT0 )
  {
    DoWork0( i ); // 假設這里不改變CONSTANT0的值
  }
  else
  {
    DoWork1( i ); // 假設這里不改變CONSTANT0的值
  }
}
if( CONSTANT0 )
{
  for( i ... )
  {
    DoWork0( i );
  }
}
else
{
  for( i ... )
  {
    DoWork1( i );
  }
}
  假如已經知道if()的值,這樣可以避免重復計算。雖然不好的代碼中的分支可以簡單地猜測,但是由于推薦的代碼在進入循環前分支已經確定,就可以減少對分支猜測的依靠。   把本地函數聲明為靜態的(static)

  假如一個函數在實現它的文件外未被使用的話,把它聲明為靜態的(static)以強制使用內部連接。否則,默認的情況下會把函數定義為外部連接。這樣可能會影響某些編譯器的優化——比如,自動內聯。

  考慮動態內存分配

  動態內存分配(C++中的";new";)可能總是為長的基本類型(四字對齊)返回一個已經對齊的指針。但是假如不能保證對齊,使用以下代碼來實現四字對齊。這段代碼假設指針可以映射到 long 型。

  例子

  double* p = (double*)new BYTE[sizeof(double) * number_of_doubles+7L];
double* np = (double*)((long(p) + 7L) &; –8L);
  現在,你可以使用 np 代替 p 來訪問數據。注重:釋放儲存空間時仍然應該用delete p。

  使用顯式的并行代碼

  盡可能把長的有依靠的代碼鏈分解成幾個可以在流水線執行單元中并行執行的沒有依靠的代碼鏈。因為浮點操作有很長的潛伏期,所以不管它被映射成 x87 或 3DNow! 指令,這都很重要。很多高級語言,包括C++,并不對產生的浮點表達式重新排序,因為那是一個相當復雜的過程。需要注重的是,重排序的代碼和原來的代碼在代數上一致并不等價于計算結果一致,因為浮點操作缺乏精確度。在一些情況下,這些優化可能導致意料之外的結果。幸運的是,在大部分情況下,最后結果可能只有最不重要的位(即最低位)是錯誤的。

  不好的代碼 推薦的代碼

double a[100], sum;
int i;
sum = 0.0f;
for (i=0; i<;100; i++)
  sum += a[i];

double a[100], sum1, sum2, sum3, sum4, sum;
int i;
sum1 = sum2 = sum3 = sum4 = 0.0;
for (i = 0; i <; 100; i += 4)
{
  sum1 += a[i];
  sum2 += a[i+1];
  sum3 += a[i+2];
  sum4 += a[i+3];
}
sum = (sum4+sum3)+(sum1+sum2);
  要注重的是:使用4 路分解是因為這樣使用了4階段流水線浮點加法,浮點加法的每一個階段占用一個時鐘周期,保證了最大的資源利用率。
QQ病毒 騰訊QQ空間代碼專題 PPT教程專題 ADSL應用面面俱到 fireworks教程專題 計算機和網絡技術基礎知識 校園網專題 網吧技術專題

  提出公共子表達式

  在某些情況下,C++編譯器不能從浮點表達式中提出公共的子表達式,因為這意味著相當于對表達式重新排序。需要非凡指出的是,編譯器在提取公共子表達式前不能按照代數的等價關系重新安排表達式。這時,程序員要手動地提出公共的子表達式(在VC.net里有一項“全局優化”選項可以完成此工作,但效果就不得而知了)。

推薦的代碼

float a, b, c, d, e, f;
...
e = b * c / d;
f = b / d * a;
float a, b, c, d, e, f;
...
const float t(b / d);
e = c * t;
f = a * t;
推薦的代碼

float a, b, c, e, f;
...
e = a / c;
f = b / c;
float a, b, c, e, f;
...
const float t(1.0f / c);
e = a * t;
f = b * t;
  結構體成員的布局

  很多編譯器有“使結構體字,雙字或四字對齊”的選項。但是,還是需要改善結構體成員的對齊,有些編譯器可能分配給結構體成員空間的順序與他們聲明的不同。但是,有些編譯器并不提供這些功能,或者效果不好。所以,要在付出最少代價的情況下實現最好的結構體和結構體成員對齊,建議采取這些方法:

  按類型長度排序

  把結構體的成員按照它們的類型長度排序,聲明成員時把長的類型放在短的前面。

  把結構體填充成最長類型長度的整倍數

  把結構體填充成最長類型長度的整倍數。照這樣,假如結構體的第一個成員對齊了,所有整個結構體自然也就對齊了。下面的例子演示了如何對結構體成員進行重新排序:

  不好的代碼,普通順序 推薦的代碼,新的順序并手動填充了幾個字節

struct
{
  char a[5];
  long k;
  double x;
} baz;
struct
{
  double x;
  long k;
  char a[5];
char pad[7];
} baz;
  這個規則同樣適用于類的成員的布局。

  按數據類型的長度排序本地變量

  當編譯器分配給本地變量空間時,它們的順序和它們在源代碼中聲明的順序一樣,和上一條規則一樣,應該把長的變量放在短的變量前面。假如第一個變量對齊了,其它變量就會連續的存放,而且不用填充字節自然就會對齊。有些編譯器在分配變量時不會自動改變變量順序,有些編譯器不能產生4字節對齊的棧,所以4字節可能不對齊。下面這個例子演示了本地變量聲明的重新排序:

  不好的代碼,普通順序 推薦的代碼,改進的順序

short ga, gu, gi;
long foo, bar;
double x, y, z[3];
char a, b;
float baz;
double z[3];
double x, y;
long foo, bar;
float baz;
short ga, gu, gi;
  避免不必要的整數除法

  整數除法是整數運算中最慢的,所以應該盡可能避免。一種可能減少整數除法的地方是連除,這里除法可以由乘法代替。這個替換的副作用是有可能在算乘積時會溢出,所以只能在一定范圍的除法中使用。

  不好的代碼 推薦的代碼

int i, j, k, m;
m = i / j / k;
int i, j, k, m;
m = i / (j * k);
  把頻繁使用的指針型參數拷貝到本地變量

  避免在函數中頻繁使用指針型參數指向的值。因為編譯器不知道指針之間是否存在沖突,所以指針型參數往往不能被編譯器優化。這樣是數據不能被存放在寄存器中,而且明顯地占用了內存帶寬。注重,很多編譯器有“假設不沖突”優化開關(在VC里必須手動添加編譯器命令行/Oa或/Ow),這答應編譯器假設兩個不同的指針總是有不同的內容,這樣就不用把指針型參數保存到本地變量。否則,請在函數一開始把指針指向的數據保存到本地變量。假如需要的話,在函數結束前拷貝回去。   不好的代碼 推薦的代碼

?/ 假設 q != r
void isqrt(unsigned long a, unsigned long* q, unsigned long* r)
{
  *q = a;
  if (a >; 0)
  {
    while (*q >; (*r = a / *q))
    {
      *q = (*q + *r) >;>; 1;
    }
  }
  *r = a - *q * *q;
}
// 假設 q != r
void isqrt(unsigned long a, unsigned long* q, unsigned long* r)
{
  unsigned long qq, rr;
  qq = a;
  if (a >; 0)
  {
    while (qq >; (rr = a / qq))
    {
      qq = (qq + rr) >;>; 1;
    }
  }
  rr = a - qq * qq;
  *q = qq;
  *r = rr;
}


賦值與初始化
先看看以下代碼:

class CInt
{
  int m_i;

public:
  CInt(int a = 0):m_i(a) { cout <;<; ";CInt"; <;<; endl; }
  ~CInt() { cout <;<; ";~CInt"; <;<; endl; }

  CInt Operator + (const CInt&; a) { return CInt(m_i + a.GetInt()); }

  void SetInt(const int i)  { m_i = i; }
  int GetInt() const      { return m_i; }
};
不好的代碼 推薦的代碼
void main()
{
  CInt a, b, c;
  a.SetInt(1);
  b.SetInt(2);
  c = a + b;
}
void main()
{
  CInt a(1), b(2);
  CInt c(a + b);
}
  這兩段代碼所作的事都一樣,但那一個更好呢?看看輸出結果就會發現,不好的代碼輸出了四個";CInt";和四個";~CInt";,而推薦的代碼只輸出三個。也就是說,第二個例子比第一個例子少生成一次臨時對象。Why? 請注重,第一個中的c用的是先聲明再賦值的方法,第二個用的是初始化的方法,它們有本質的區別。第一個例子的";c = a + b";先生成一個臨時對象用來保存a + b的值,再把該臨時對象用位拷貝的方法給c賦值,然后臨時對象被銷毀。這個臨時對象就是那個多出來的對象。第二個例子直接用拷貝構造函數的方法對c初始化,不產生臨時對象。所以,盡量在需要使用一個對象時才聲明,并用初始化的方法賦初值。

  盡量使用成員初始化列表

  在初始化類的成員時,盡量使用成員初始化列表而不是傳統的賦值方式。

  不好的代碼 推薦的代碼


籧lass CMyClass
{
  string strName;

public:
  CMyClass(const string&; str);
};

CMyClass::CMyClass(const string&; str)
{
  strName = str;
}
class CMyClass
{
  string strName;
  int i;

public:
  CMyClass(const string&; str);
};

CMyClass::CMyClass(const string&;str)
  : strName(str)
{
}
  不好的例子用的是賦值的方式。這樣,strName會先被建立(調用了string的默認構造函數),再由參數str賦值。而推薦的例子用的是成員初始化列表,strName直接構造為str,少調用一次默認構造函數,還少了一些安全隱患。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
97视频免费看| 欧美日韩国产在线看| 国产精品丝袜久久久久久不卡| 午夜精品一区二区三区在线视频| 亚洲欧洲日产国码av系列天堂| 欧美在线视频网| 日韩欧美视频一区二区三区| 欧美性xxxx极品hd欧美风情| 伦伦影院午夜日韩欧美限制| 在线观看亚洲视频| 国产精品精品视频一区二区三区| 欧美视频在线看| 亚洲网站在线观看| 久久久女人电视剧免费播放下载| 亚洲嫩模很污视频| 国产日韩av高清| 亚洲欧洲一区二区三区久久| 最近2019中文字幕大全第二页| 亚洲精品一区二区在线| 国产精品久久婷婷六月丁香| 亚洲国产精品视频在线观看| 国产成人精品久久二区二区| 亚洲欧美中文日韩v在线观看| 在线成人免费网站| 深夜福利91大全| 国产一区二区黑人欧美xxxx| 亚洲日本欧美日韩高观看| 欧美激情久久久久久| 国产国语videosex另类| 亚洲欧美在线免费观看| 久久九九有精品国产23| 日韩免费在线免费观看| 精品久久中文字幕久久av| 国产精品成人aaaaa网站| 亚洲精品久久久久久久久| 亚洲桃花岛网站| 亚洲国产一区二区三区四区| 亚洲欧美制服中文字幕| 91丝袜美腿美女视频网站| 精品久久久久久久久久久久| 久久久久一本一区二区青青蜜月| 亚洲免费伊人电影在线观看av| 2023亚洲男人天堂| 国产精品视频午夜| 久久视频国产精品免费视频在线| 国产精品96久久久久久| 97精品久久久| 国产精品男人的天堂| 亚洲视频一区二区三区| 91在线看www| 亚洲美女又黄又爽在线观看| 91av免费观看91av精品在线| 久久亚洲精品中文字幕冲田杏梨| 亚洲第一视频在线观看| 美女999久久久精品视频| 亚洲**2019国产| 高清欧美性猛交xxxx| 国产亚洲欧美日韩精品| 日本午夜精品理论片a级appf发布| 国产精品久久久久久久一区探花| 高清亚洲成在人网站天堂| 91精品成人久久| 亚洲偷熟乱区亚洲香蕉av| 狠狠躁18三区二区一区| 国产在线视频一区| 国产精国产精品| 777777777亚洲妇女| 亚洲精品欧美日韩| 日韩美女免费视频| 欧美激情三级免费| 久久精品国产成人精品| 亚洲综合色av| 国产成人精品免费久久久久| 久久久久久网址| 日韩在线观看免费| 国产一区二区三区三区在线观看| 成人av资源在线播放| 国产精品欧美久久久| 久久精品久久精品亚洲人| 色婷婷久久一区二区| 午夜精品一区二区三区在线| 91精品国产91久久久久| 国产精品爱啪在线线免费观看| 97人洗澡人人免费公开视频碰碰碰| 亚洲色图五月天| 午夜欧美大片免费观看| 亚洲美女喷白浆| 一区二区av在线| 欧美色道久久88综合亚洲精品| 欧洲亚洲在线视频| 一色桃子一区二区| 久久久成人av| 自拍视频国产精品| 国产精品91免费在线| 色老头一区二区三区在线观看| 免费91麻豆精品国产自产在线观看| 久久精品视频99| 欧美日韩xxx| 最近的2019中文字幕免费一页| 国产成人精品av在线| 一区二区三区视频在线| 久久视频中文字幕| 91久久在线视频| 国产精品女主播视频| 91在线免费观看网站| 欧美成人一区在线| 国产日韩欧美在线观看| 欧美裸身视频免费观看| 亚洲综合国产精品| 欧洲日韩成人av| 亚洲最大av网站| 欧美在线精品免播放器视频| 久久久亚洲欧洲日产国码aⅴ| 色综合色综合久久综合频道88| 亚洲最新av网址| 国产精品色婷婷视频| 成年无码av片在线| 成人在线播放av| 久久久99久久精品女同性| 96pao国产成视频永久免费| 成年无码av片在线| 性日韩欧美在线视频| 亚洲精品小视频| 国产69精品久久久久99| 欧美专区在线播放| 精品久久久91| 久久99亚洲热视| 亚洲成人精品视频| 亚洲欧美日本伦理| 日韩欧美在线观看视频| 亚洲国产美女精品久久久久∴| 成人免费福利在线| 日韩精品在线电影| 精品女厕一区二区三区| 欧美激情精品久久久久久免费印度| 日韩美女免费观看| 久久精品国产一区二区电影| 45www国产精品网站| 日韩免费在线视频| 久久国产精品久久久久久| 91福利视频在线观看| 国产免费一区二区三区在线观看| 国内精品久久影院| 福利一区福利二区微拍刺激| 日本一区二区三区四区视频| 亚洲综合在线中文字幕| 亚洲专区国产精品| 国产精品久久一区| 久久久久久香蕉网| 亚洲久久久久久久久久| 久久99国产综合精品女同| 久久天天躁狠狠躁夜夜av| 热久久免费视频精品| 亚洲最大的免费| 亚洲人av在线影院| 国产精品福利观看| 久久久噜久噜久久综合| 国产97在线视频| 久久综合伊人77777蜜臀| 精品亚洲精品福利线在观看| 久久久久久成人| 中文字幕在线观看亚洲| 欧洲亚洲妇女av| 成人免费看片视频|