青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

C++ Programmer's Cookbook

{C++ 基礎(chǔ)} {C++ 高級} {C#界面,C++核心算法} {設(shè)計模式} {C#基礎(chǔ)}

C++代碼優(yōu)化(二)

 談到優(yōu)化,很多人都會直接想到匯編。難道優(yōu)化只能在匯編層次嗎?當(dāng)然不是,C++層次一樣可以作代碼優(yōu)化,其中有些常常是意想不到的。在C++層次進(jìn)行優(yōu)化,比在匯編層次優(yōu)化具有更好的移植性,應(yīng)該是優(yōu)化中的首選做法。
1.確定浮點(diǎn)型變量和表達(dá)式是 float 型
    為了讓編譯器產(chǎn)生更好的代碼(比如說產(chǎn)生3DNow! 或SSE指令的代碼),必須確定浮點(diǎn)型變量和表達(dá)式是 float 型的。要特別注意的是,以 ";F"; 或 ";f"; 為后綴(比如:3.14f)的浮點(diǎn)常量才是 float 型,否則默認(rèn)是 double 型。為了避免 float 型參數(shù)自動轉(zhuǎn)化為 double,請在函數(shù)聲明時使用 float。
2.使用32位的數(shù)據(jù)類型
  編譯器有很多種,但它們都包含的典型的32位類型是:int,signed,signed int,unsigned,unsigned int,long,signed long,long int,signed long int,unsigned long,unsigned long int。盡量使用32位的數(shù)據(jù)類型,因為它們比16位的數(shù)據(jù)甚至8位的數(shù)據(jù)更有效率。
3.明智使用有符號整型變量
  在很多情況下,你需要考慮整型變量是有符號還是無符號類型的。比如,保存一個人的體重數(shù)據(jù)時不可能出現(xiàn)負(fù)數(shù),所以不需要使用有符號類型。但是,如果是要保存溫度數(shù)據(jù),就必須使用到有符號的變量。
  在許多地方,考慮是否使用有符號的變量是必要的。在一些情況下,有符號的運(yùn)算比較快;但在一些情況下卻相反。
  比如:整型到浮點(diǎn)轉(zhuǎn)化時,使用大于16位的有符號整型比較快。因為x86構(gòu)架中提供了從有符號整型轉(zhuǎn)化到浮點(diǎn)型的指令,但沒有提供從無符號整型轉(zhuǎn)化到浮點(diǎn)的指令。看看編譯器產(chǎn)生的匯編代碼:
  不好的代碼:
編譯前      編譯后
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]
  上面的代碼比較慢。不僅因為指令數(shù)目比較多,而且由于指令不能配對造成的FLID指令被延遲執(zhí)行。最好用以下代碼代替:
    推薦的代碼:
編譯前     編譯后
double x;    fild dword ptr
int i;     fstp qword ptr [x]
x = i;
  在整數(shù)運(yùn)算中計算商和余數(shù)時,使用無符號類型比較快。以下這段典型的代碼是編譯器產(chǎn)生的32位整型數(shù)除以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;
 總結(jié):
 無符號類型用于:除法和余數(shù),循環(huán)計數(shù),數(shù)組下標(biāo)
  有符號類型用于:整型到浮點(diǎn)的轉(zhuǎn)化
4.while VS. for
  在編程中,我們常常需要用到無限循環(huán),常用的兩種方法是while (1) 和 for (;;)。這兩種方法效果完全一樣,但那一種更好呢?然我們看看它們編譯后的代碼:
編譯前      編譯后
while (1);     mov eax,1
     test eax,eax
     je foo+23h
     jmp foo+18h
編譯前      編譯后 
for (;;);     jmp foo+23h
  一目了然,for (;;)指令少,不占用寄存器,而且沒有判斷跳轉(zhuǎn),比while (1)好。
5.使用數(shù)組型代替指針型
  使用指針會使編譯器很難優(yōu)化它。因為缺乏有效的指針代碼優(yōu)化的方法,編譯器總是假設(shè)指針可以訪問內(nèi)存的任意地方,包括分配給其他變量的儲存空間。所以為了編譯器產(chǎn)生優(yōu)化得更好的代碼,要避免在不必要的地方使用指針。一個典型的例子是訪問存放在數(shù)組中的數(shù)據(jù)。C++ 允許使用操作符 [] 或指針來訪問數(shù)組,使用數(shù)組型代碼會讓優(yōu)化器減少產(chǎn)生不安全代碼的可能性。比如,x[0] 和x[2] 不可能是同一個內(nèi)存地址,但 *p 和 *q 可能。強(qiáng)烈建議使用數(shù)組型,因為這樣可能會有意料之外的性能提升。
    不好的代碼
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;      // 寫入轉(zhuǎn)換了的 x
    dp = vv->;x * *m ++;
    dp += vv->;y * *m ++;
    dp += vv->;z * *m ++;
    dp += vv->;w * *m ++;
    *res ++ = dp;     // 寫入轉(zhuǎn)換了的 y
    dp = vv->;x * *m ++;
    dp += vv->;y * *m ++;
    dp += vv->;z * *m ++;
    dp += vv->;w * *m ++;
    *res ++ = dp;    // 寫入轉(zhuǎn)換了的 z
    dp = vv->;x * *m ++;
    dp += vv->;y * *m ++;
    dp += vv->;z * *m ++;
    dp += vv->;w * *m ++;
    *res ++ = dp;    // 寫入轉(zhuǎn)換了的 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];
  }
}
  注意: 源代碼的轉(zhuǎn)化是與編譯器的代碼發(fā)生器相結(jié)合的。從源代碼層次很難控制產(chǎn)生的機(jī)器碼。依靠編譯器和特殊的源代碼,有可能指針型代碼編譯成的機(jī)器碼比同等條件下的數(shù)組型代碼運(yùn)行速度更快。明智的做法是在源代碼轉(zhuǎn)化后檢查性能是否真正提高了,再選擇使用指針型還是數(shù)組型。
6.充分分解小的循環(huán)
  要充分利用CPU的指令緩存,就要充分分解小的循環(huán)。特別是當(dāng)循環(huán)體本身很小的時候,分解循環(huán)可以提高性能。BTW:很多編譯器并不能自動分解循環(huán)。
不好的代碼 推薦的代碼
// 3D轉(zhuǎn)化:把矢量 V 和 4x4 矩陣 M 相乘
for (i = 0; i <; 4; i ++)
{
  r = 0;
  for (j = 0; j <; 4; j ++)
  {
    r += M[j]*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];
7.避免沒有必要的讀寫依賴
  當(dāng)數(shù)據(jù)保存到內(nèi)存時存在讀寫依賴,即數(shù)據(jù)必須在正確寫入后才能再次讀取。雖然AMD Athlon等CPU有加速讀寫依賴延遲的硬件,允許在要保存的數(shù)據(jù)被寫入內(nèi)存前讀取出來,但是,如果避免了讀寫依賴并把數(shù)據(jù)保存在內(nèi)部寄存器中,速度會更快。在一段很長的又互相依賴的代碼鏈中,避免讀寫依賴顯得尤其重要。如果讀寫依賴發(fā)生在操作數(shù)組時,許多編譯器不能自動優(yōu)化代碼以避免讀寫依賴。所以推薦程序員手動去消除讀寫依賴,舉例來說,引進(jìn)一個可以保存在寄存器中的臨時變量。這樣可以有很大的性能提升。下面一段代碼是一個例子:
    不好的代碼
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;
}
8.Switch 的用法
  Switch 可能轉(zhuǎn)化成多種不同算法的代碼。其中最常見的是跳轉(zhuǎn)表和比較鏈/樹。推薦對case的值依照發(fā)生的可能性進(jìn)行排序,把最有可能的放在第一個,當(dāng)switch用比較鏈的方式轉(zhuǎn)化時,這樣可以提高性能。此外,在case中推薦使用小的連續(xù)的整數(shù),因為在這種情況下,所有的編譯器都可以把switch 轉(zhuǎn)化成跳轉(zhuǎn)表。
    不好的代碼
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;
}
9.所有函數(shù)都應(yīng)該有原型定義
  一般來說,所有函數(shù)都應(yīng)該有原型定義。原型定義可以傳達(dá)給編譯器更多的可能用于優(yōu)化的信息。
  盡可能使用常量(const)。C++ 標(biāo)準(zhǔn)規(guī)定,如果一個const聲明的對象的地址不被獲取,允許編譯器不對它分配儲存空間。這樣可以使代碼更有效率,而且可以生成更好的代碼。
10.提升循環(huán)的性能
  要提升循環(huán)的性能,減少多余的常量計算非常有用(比如,不隨循環(huán)變化的計算)。
  不好的代碼(在for()中包含不變的if()) 推薦的代碼
for( i ... )
{
  if( CONSTANT0 )
  {
    DoWork0( i ); // 假設(shè)這里不改變CONSTANT0的值
  }
  else
  {
    DoWork1( i ); // 假設(shè)這里不改變CONSTANT0的值
  }
}
if( CONSTANT0 )
{
  for( i ... )
  {
    DoWork0( i );
  }
}
else
{
  for( i ... )
  {
    DoWork1( i );
  }
}
  如果已經(jīng)知道if()的值,這樣可以避免重復(fù)計算。雖然不好的代碼中的分支可以簡單地預(yù)測,但是由于推薦的代碼在進(jìn)入循環(huán)前分支已經(jīng)確定,就可以減少對分支預(yù)測的依賴。   把本地函數(shù)聲明為靜態(tài)的(static)
  如果一個函數(shù)在實現(xiàn)它的文件外未被使用的話,把它聲明為靜態(tài)的(static)以強(qiáng)制使用內(nèi)部連接。否則,默認(rèn)的情況下會把函數(shù)定義為外部連接。這樣可能會影響某些編譯器的優(yōu)化——比如,自動內(nèi)聯(lián)。
11.考慮動態(tài)內(nèi)存分配
  動態(tài)內(nèi)存分配(C++中的";new";)可能總是為長的基本類型(四字對齊)返回一個已經(jīng)對齊的指針。但是如果不能保證對齊,使用以下代碼來實現(xiàn)四字對齊。這段代碼假設(shè)指針可以映射到 long 型。
  例子
  double* p = (double*)new BYTE[sizeof(double) * number_of_doubles+7L];
    double* np = (double*)((long(p) + 7L) &; –8L);
  現(xiàn)在,你可以使用 np 代替 p 來訪問數(shù)據(jù)。注意:釋放儲存空間時仍然應(yīng)該用delete p。
12.使用顯式的并行代碼
  盡可能把長的有依賴的代碼鏈分解成幾個可以在流水線執(zhí)行單元中并行執(zhí)行的沒有依賴的代碼鏈。因為浮點(diǎn)操作有很長的潛伏期,所以不管它被映射成 x87 或 3DNow! 指令,這都很重要。很多高級語言,包括C++,并不對產(chǎn)生的浮點(diǎn)表達(dá)式重新排序,因為那是一個相當(dāng)復(fù)雜的過程。需要注意的是,重排序的代碼和原來的代碼在代數(shù)上一致并不等價于計算結(jié)果一致,因為浮點(diǎn)操作缺乏精確度。在一些情況下,這些優(yōu)化可能導(dǎo)致意料之外的結(jié)果。幸運(yùn)的是,在大部分情況下,最后結(jié)果可能只有最不重要的位(即最低位)是錯誤的。
  不好的代碼
double a[100], sum;
int i;
sum = 0.0f;
for (i=0; i<;100; i++)
  sum += a;
    推薦的代碼
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;
  sum2 += a[i+1];
  sum3 += a[i+2];
  sum4 += a[i+3];
}
sum = (sum4+sum3)+(sum1+sum2);
  要注意的是:使用4 路分解是因為這樣使用了4階段流水線浮點(diǎn)加法,浮點(diǎn)加法的每一個階段占用一個時鐘周期,保證了最大的資源利用率。
13.提出公共子表達(dá)式
  在某些情況下,C++編譯器不能從浮點(diǎn)表達(dá)式中提出公共的子表達(dá)式,因為這意味著相當(dāng)于對表達(dá)式重新排序。需要特別指出的是,編譯器在提取公共子表達(dá)式前不能按照代數(shù)的等價關(guān)系重新安排表達(dá)式。這時,程序員要手動地提出公共的子表達(dá)式(在VC.net里有一項“全局優(yōu)化”選項可以完成此工作,但效果就不得而知了)。
推薦的代碼
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;
14.結(jié)構(gòu)體成員的布局
  很多編譯器有“使結(jié)構(gòu)體字,雙字或四字對齊”的選項。但是,還是需要改善結(jié)構(gòu)體成員的對齊,有些編譯器可能分配給結(jié)構(gòu)體成員空間的順序與他們聲明的不同。但是,有些編譯器并不提供這些功能,或者效果不好。所以,要在付出最少代價的情況下實現(xiàn)最好的結(jié)構(gòu)體和結(jié)構(gòu)體成員對齊,建議采取這些方法:
  A按類型長度排序
  把結(jié)構(gòu)體的成員按照它們的類型長度排序,聲明成員時把長的類型放在短的前面。
  把結(jié)構(gòu)體填充成最長類型長度的整倍數(shù)
  把結(jié)構(gòu)體填充成最長類型長度的整倍數(shù)。照這樣,如果結(jié)構(gòu)體的第一個成員對齊了,所有整個結(jié)構(gòu)體自然也就對齊了。下面的例子演示了如何對結(jié)構(gòu)體成員進(jìn)行重新排序:
  不好的代碼,普通順序 推薦的代碼,新的順序并手動填充了幾個字節(jié)
struct
{
  char a[5];
  long k;
  double x;
} baz;
struct
{
  double x;
  long k;
  char a[5];
char pad[7];
} baz;

  這個規(guī)則同樣適用于類的成員的布局。
  B按數(shù)據(jù)類型的長度排序本地變量
  當(dāng)編譯器分配給本地變量空間時,它們的順序和它們在源代碼中聲明的順序一樣,和上一條規(guī)則一樣,應(yīng)該把長的變量放在短的變量前面。如果第一個變量對齊了,其它變量就會連續(xù)的存放,而且不用填充字節(jié)自然就會對齊。有些編譯器在分配變量時不會自動改變變量順序,有些編譯器不能產(chǎn)生4字節(jié)對齊的棧,所以4字節(jié)可能不對齊。下面這個例子演示了本地變量聲明的重新排序:
  不好的代碼,普通順序 推薦的代碼,改進(jìn)的順序
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;
14.避免不必要的整數(shù)除法
  整數(shù)除法是整數(shù)運(yùn)算中最慢的,所以應(yīng)該盡可能避免。一種可能減少整數(shù)除法的地方是連除,這里除法可以由乘法代替。這個替換的副作用是有可能在算乘積時會溢出,所以只能在一定范圍的除法中使用。
  不好的代碼 推薦的代碼
int i, j, k, m;
m = i / j / k;
int i, j, k, m;
m = i / (j * k);
15.把頻繁使用的指針型參數(shù)拷貝到本地變量
  避免在函數(shù)中頻繁使用指針型參數(shù)指向的值。因為編譯器不知道指針之間是否存在沖突,所以指針型參數(shù)往往不能被編譯器優(yōu)化。這樣是數(shù)據(jù)不能被存放在寄存器中,而且明顯地占用了內(nèi)存帶寬。注意,很多編譯器有“假設(shè)不沖突”優(yōu)化開關(guān)(在VC里必須手動添加編譯器命令行/Oa或/Ow),這允許編譯器假設(shè)兩個不同的指針總是有不同的內(nèi)容,這樣就不用把指針型參數(shù)保存到本地變量。否則,請在函數(shù)一開始把指針指向的數(shù)據(jù)保存到本地變量。如果需要的話,在函數(shù)結(jié)束前拷貝回去。   
    不好的代碼
// 假設(shè) 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;
}
    推薦的代碼
// 假設(shè) 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;
}
16.賦值與初始化
先看看以下代碼:
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);
}
  這兩段代碼所作的事都一樣,但那一個更好呢?看看輸出結(jié)果就會發(fā)現(xiàn),不好的代碼輸出了四個";CInt";和四個";~CInt";,而推薦的代碼只輸出三個。也就是說,第二個例子比第一個例子少生成一次臨時對象。Why? 請注意,第一個中的c用的是先聲明再賦值的方法,第二個用的是初始化的方法,它們有本質(zhì)的區(qū)別。第一個例子的";c = a + b";先生成一個臨時對象用來保存a + b的值,再把該臨時對象用位拷貝的方法給c賦值,然后臨時對象被銷毀。這個臨時對象就是那個多出來的對象。第二個例子直接用拷貝構(gòu)造函數(shù)的方法對c初始化,不產(chǎn)生臨時對象。所以,盡量在需要使用一個對象時才聲明,并用初始化的方法賦初值。
17.盡量使用成員初始化列表
  在初始化類的成員時,盡量使用成員初始化列表而不是傳統(tǒng)的賦值方式。
  不好的代碼
class 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會先被建立(調(diào)用了string的默認(rèn)構(gòu)造函數(shù)),再由參數(shù)str賦值。而推薦的例子用的是成員初始化列表,strName直接構(gòu)造為str,少調(diào)用一次默認(rèn)構(gòu)造函數(shù),還少了一些安全隱患。

posted on 2007-08-14 17:17 夢在天涯 閱讀(4800) 評論(3)  編輯 收藏 引用 所屬分類: CPlusPlus

評論

# re: C++代碼優(yōu)化(二) 2007-08-14 17:17 夢在天涯

轉(zhuǎn)自松鼠的c++博客  回復(fù)  更多評論   

# re: C++代碼優(yōu)化(二) 2007-08-14 20:59 pass86

必要的時候可以考慮下。  回復(fù)  更多評論   

# re: C++代碼優(yōu)化(二) 2008-01-08 17:03 flyswift

分析得很詳細(xì)啊,不過平時編寫的時候不可能注意到那么多,特別是一個項目不可能一個人編寫..
所以,一般都是用VTune找出瓶頸,然后再針對性的優(yōu)化.  回復(fù)  更多評論   

公告

EMail:itech001#126.com

導(dǎo)航

統(tǒng)計

  • 隨筆 - 461
  • 文章 - 4
  • 評論 - 746
  • 引用 - 0

常用鏈接

隨筆分類

隨筆檔案

收藏夾

Blogs

c#(csharp)

C++(cpp)

Enlish

Forums(bbs)

My self

Often go

Useful Webs

Xml/Uml/html

搜索

  •  

積分與排名

  • 積分 - 1815011
  • 排名 - 5

最新評論

閱讀排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
      <noscript id="pjuwb"></noscript>
            <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
              <dd id="pjuwb"></dd>
              <abbr id="pjuwb"></abbr>
              性欧美大战久久久久久久久| 最新国产の精品合集bt伙计| 国产亚洲精品bv在线观看| 欧美日韩国产一区二区三区| 美女视频黄 久久| 欧美一区二区视频免费观看| 欧美专区在线| 久久综合网hezyo| 欧美精品久久一区二区| 国产精品国码视频| 国产毛片一区二区| 1000部国产精品成人观看| 伊人久久婷婷色综合98网| 亚洲人成小说网站色在线| 亚洲图片欧美日产| 久久久久久久综合狠狠综合| 欧美成人精品| 亚洲美女视频| 久久av一区二区三区漫画| 蜜桃av一区二区三区| 欧美性片在线观看| 精品动漫3d一区二区三区免费| 亚洲国产精品久久人人爱蜜臀| 日韩视频在线永久播放| 性久久久久久久久| 欧美激情精品久久久久久大尺度| 日韩亚洲视频在线| 久久三级视频| 国产精品色婷婷| 亚洲欧洲三级| 久久国内精品视频| 亚洲美女在线视频| 久久天堂精品| 国产精品女主播| 亚洲精品乱码久久久久久久久| 欧美一级艳片视频免费观看| 亚洲第一视频| 久久激情一区| 国产精品v欧美精品v日本精品动漫| 激情视频一区二区三区| 亚洲一区二区三区激情| 亚洲第一伊人| 久久精品一区蜜桃臀影院| 欧美肉体xxxx裸体137大胆| 在线观看亚洲视频啊啊啊啊| 亚洲一区二区成人| 亚洲盗摄视频| 免费观看30秒视频久久| 国产专区一区| 欧美在线视频日韩| 亚洲一本视频| 国产精品久久久久一区| 亚洲精品一区二区三区蜜桃久 | 国产精品国产| 亚洲精品美女免费| 亚洲精品国产精品乱码不99按摩| 亚洲婷婷在线| 欧美日韩免费看| 亚洲人成网站777色婷婷| 久久在线视频| 久久精品国产第一区二区三区| 欧美天天综合网| 99人久久精品视频最新地址| 亚洲区欧美区| 欧美日韩综合另类| 午夜精品久久久久影视| 亚洲视频日本| 国产伦精品免费视频| 欧美在线免费播放| 欧美一区二区三区在线视频| 在线播放日韩欧美| 欧美激情按摩在线| 欧美成人在线网站| 亚洲理论在线观看| 99国产精品久久久久久久| 欧美日韩三区四区| 亚洲伊人伊色伊影伊综合网| 亚洲午夜黄色| 国产一区二区精品丝袜| 久久阴道视频| 欧美好吊妞视频| 亚洲天堂av图片| 亚洲欧美日韩综合aⅴ视频| 国产一区二区三区av电影| 免费成人av在线看| 欧美人妖另类| 欧美自拍丝袜亚洲| 久久午夜电影| 亚洲一区二区三区免费观看| 校园激情久久| 一区二区成人精品| 性欧美1819sex性高清| 91久久精品网| 亚洲综合第一页| 亚洲国产美女久久久久| 一级成人国产| 亚洲电影免费在线| 亚洲午夜精品国产| 亚洲高清在线观看一区| 在线亚洲成人| 亚洲精品久久7777| 欧美亚洲专区| 一本色道久久综合亚洲精品高清 | 国产精品狼人久久影院观看方式| 久久久久这里只有精品| 欧美美女视频| 久久亚洲综合| 国产精品理论片| 亚洲欧洲日夜超级视频| 韩国视频理论视频久久| 亚洲视频精品在线| 亚洲伦理久久| 老巨人导航500精品| 欧美日韩国产色视频| 在线观看日韩欧美| 亚洲午夜一二三区视频| 亚洲日产国产精品| 欧美一区二区三区在线视频| 亚洲主播在线观看| 欧美国产日韩精品免费观看| 免费观看30秒视频久久| 国产人久久人人人人爽| 99综合在线| aa国产精品| 欧美精品色一区二区三区| 欧美肥婆bbw| 在线观看国产日韩| 久久国产视频网站| 久久精品卡一| 国产在线拍揄自揄视频不卡99| 亚洲无玛一区| 欧美一区激情| 国产情人节一区| 亚洲欧美中文另类| 性做久久久久久免费观看欧美| 欧美日韩中文字幕精品| 日韩午夜免费| 亚洲一级在线观看| 国产精品久久久久久久久久三级| 99re亚洲国产精品| 亚洲一区中文| 国产精品视频区| 西瓜成人精品人成网站| 久久九九精品| 在线观看一区视频| 欧美福利网址| av成人老司机| 欧美一区二区三区视频在线| 国产午夜精品视频| 久久九九国产精品怡红院| 欧美大片免费久久精品三p| 最新高清无码专区| 欧美午夜视频在线观看| 亚洲制服丝袜在线| 久久视频免费观看| 亚洲精品欧美精品| 国产精品久久久一区二区| 欧美亚洲免费在线| 欧美大片在线影院| 亚洲视频精选| 国产亚洲综合精品| 免费黄网站欧美| 一本大道av伊人久久综合| 久久riav二区三区| 亚洲人成网站777色婷婷| 国产精品极品美女粉嫩高清在线| 欧美亚洲综合在线| 亚洲精品乱码视频| 久久国产一二区| 一区二区国产日产| 一区在线免费观看| 国产精品成人v| 玖玖综合伊人| 亚洲主播在线| 亚洲精华国产欧美| 久久精品国内一区二区三区| 亚洲国产日韩欧美| 国产欧美va欧美不卡在线| 免费中文字幕日韩欧美| 亚洲永久免费视频| 亚洲国产一区二区精品专区| 欧美在线视频一区| 亚洲午夜在线观看视频在线| 依依成人综合视频| 久久久欧美精品sm网站| 国产伦精品一区二区三区视频黑人| 午夜亚洲福利| 日韩视频不卡中文| 欧美大尺度在线观看| 欧美在线观看一区二区| 亚洲精品中文字幕有码专区| 国产在线高清精品| 国产精品一区二区三区四区五区| 欧美精品久久久久久久免费观看 | 欧美精品激情| 玖玖玖免费嫩草在线影院一区| 亚洲在线中文字幕| 中文在线资源观看网站视频免费不卡 | 国产美女一区二区| 欧美日韩不卡一区|