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

c語(yǔ)言中可變參數(shù)函數(shù)的設(shè)計(jì)

1,首先,怎么得到參數(shù)的值。對(duì)于一般的函數(shù),我們可以通過(guò)參數(shù)對(duì)應(yīng)在參數(shù)列表里的標(biāo)識(shí)符來(lái)得到。但是參數(shù)可變函數(shù)那些可變的參數(shù)是沒(méi)有參數(shù)標(biāo)識(shí)符的,它只有“…”,所以通過(guò)標(biāo)識(shí)符來(lái)得到是不可能的,我們只有另辟途徑。

我們知道函數(shù)調(diào)用時(shí)都會(huì)分配棧空間,而函數(shù)調(diào)用機(jī)制中的棧結(jié)構(gòu)如下圖所示:

                       |     ......     |

                       ------------------

                       |     參數(shù)2      |

                       ------------------

                       |     參數(shù)1      |

                       ------------------

                       |    返回地址    |

                       ------------------

                       |調(diào)用函數(shù)運(yùn)行狀態(tài)|

                       ------------------

可見(jiàn),參數(shù)是連續(xù)存儲(chǔ)在棧里面的,那么也就是說(shuō),我們只要得到可變參數(shù)的前一個(gè)參數(shù)的地址,就可以通過(guò)指針訪問(wèn)到那些可變參數(shù)。但是怎么樣得到可變參數(shù)的前一個(gè)參數(shù)的地址呢?不知道你注意到?jīng)]有,參數(shù)可變函數(shù)在可變參數(shù)之前必有一個(gè)參數(shù)是固定的,并使用標(biāo)識(shí)符,而且通常被聲明為char*類型,printf函數(shù)也不例外。這樣的話,我們就可以通過(guò)這個(gè)參數(shù)對(duì)應(yīng)的標(biāo)識(shí)符來(lái)得到地址,從而訪問(wèn)其他參數(shù)變得可能。我們可以寫(xiě)一個(gè)測(cè)試程序來(lái)試一下:

#include <stdio.h>



void va_test(char* fmt,...);//參數(shù)可變的函數(shù)聲明



void main()

{

    int a=1,c=55;

       char b='b';

    va_test("",a,b,c);//用四個(gè)參數(shù)做測(cè)試

}



void va_test(char* fmt,...) //參數(shù)可變的函數(shù)定義,注意第一個(gè)參數(shù)為char* fmt

{

   char *p=NULL;



      p=(char *)&fmt;//注意不是指向fmt,而是指向&fmt,并且強(qiáng)制轉(zhuǎn)化為char *,以便一個(gè)一個(gè)字節(jié)訪問(wèn)

      for(int i = 0;i<16;i++)//16是通過(guò)計(jì)算的值(參數(shù)個(gè)數(shù)*4個(gè)字節(jié)),只是為了測(cè)試,暫且將就一下

      {

                printf("%.4d ",*p);//輸出p指針指向地址的值

        p++;

      }

}



編譯運(yùn)行的結(jié)果為

0056 0000 0066 0000 | 0001 0000 0000 0000 | 0098 0000 0000 0000 | 0055 0000 0000 0000



由運(yùn)行結(jié)果可見(jiàn),通過(guò)這樣方式可以逐一獲得可變參數(shù)的值。

至于為什么通常被聲明為char*類型,我們慢慢看來(lái)。

2,怎樣確定參數(shù)類型和數(shù)量

通過(guò)上述的方式,我們首先解決了取得可變參數(shù)值的問(wèn)題,但是對(duì)于一個(gè)參數(shù),值很重要,其類型同樣舉足輕重,而對(duì)于一個(gè)函數(shù)來(lái)講參數(shù)個(gè)數(shù)也非常重要,否則就會(huì)產(chǎn)生了一系列的麻煩來(lái)。通過(guò)訪問(wèn)存儲(chǔ)參數(shù)的棧空間,我們并不能得到關(guān)于類型的任何信息和參數(shù)個(gè)數(shù)的任何信息。我想你應(yīng)該想到了——使用char *參數(shù)。Printf函數(shù)就是這樣實(shí)現(xiàn)的,它把后面的可變參數(shù)類型都放到了char *指向的字符數(shù)組里,并通過(guò)%來(lái)標(biāo)識(shí)以便與其它的字符相區(qū)別,從而確定了參數(shù)類型也確定了參數(shù)個(gè)數(shù)。其實(shí),用何種方式來(lái)到達(dá)這樣的效果取決于函數(shù)的實(shí)現(xiàn)。比如說(shuō),定義一個(gè)函數(shù),預(yù)知它的可變參數(shù)類型都是int,那么固定參數(shù)完全可以用int類型來(lái)替換char*類型,因?yàn)橹灰玫絽?shù)個(gè)數(shù)就可以了。

3,言歸正傳

   我想到了這里,大概的輪廓已經(jīng)呈現(xiàn)出來(lái)了。本來(lái)想就此作罷的(我的惰性使然),但是一想到如果不具實(shí)用性便可能是一堆廢物,枉費(fèi)我打了這么些字,決定還是繼續(xù)下去。

   我是比較抵制用那些不明所以的宏定義的,所以在上面的闡述里一點(diǎn)都沒(méi)有涉及定義在<stdarg.h>的va(variable-argument)宏。事實(shí)上,當(dāng)時(shí)讓我產(chǎn)生極大疑惑和好奇的正是這幾個(gè)宏定義。但是現(xiàn)在我們不得不要去和這些宏定義打打交道,畢竟我們?cè)谟懮?jì)的時(shí)候還得用上他們,這也是我曰之為“言歸正傳”的理由。

   好了,我們來(lái)看一下那些宏定義。

   打開(kāi)<stdarg.h>文件,找一下va_*的宏定義,發(fā)現(xiàn)不單單只有一組,但是在各組定義前都會(huì)有宏編譯。宏編譯指示的是不同硬件平臺(tái)和編譯器下用怎樣的va宏定義。比較一下,不同之處主要在偏移量的計(jì)算上。我們還是拿個(gè)典型又熟悉的——X86的相關(guān)宏定義:

1)typedef char * va_list;

2)#define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )



3)#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )

4)#define va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

5)#define va_end(ap)      ( ap = (va_list)0 )



我們逐一看來(lái):

第一個(gè)我想不必說(shuō)了,類型定義罷了。第二個(gè)是頗有些來(lái)頭的,我們也不得不搞懂它,因?yàn)楹竺娴膬蓚€(gè)關(guān)鍵的宏定義都用到了。不知道你夠不夠細(xì)心,有沒(méi)有發(fā)現(xiàn)在上面的測(cè)試程序中,第二個(gè)可變參數(shù)明明是char類型,可是在輸出結(jié)果中占了4個(gè)byte。難道所有的參數(shù)都會(huì)占4個(gè)byte的空間?那如果是double類型的參數(shù),且不是會(huì)丟失數(shù)據(jù)!如果你不嫌麻煩的話,再去做個(gè)測(cè)試吧,在上面的測(cè)試程序中用一個(gè)double類型(長(zhǎng)度為8byte)和一個(gè)long double類型(長(zhǎng)度為10byte)做可變參數(shù)。發(fā)現(xiàn)什么?double類型占了8byte,而long double占了12byte。好像都是4的整數(shù)倍哦。不得不引出另一個(gè)概念了“對(duì)齊(alignment)”,所謂對(duì)齊,對(duì)Intel80x86 機(jī)器來(lái)說(shuō)就是要求每個(gè)變量的地址都是sizeof(int)的倍數(shù)。原來(lái)我們搞錯(cuò)了,char類型的參數(shù)只占了1byte,但是它后面的參數(shù)因?yàn)閷?duì)齊的關(guān)系只能跳過(guò)3byte存儲(chǔ),而那3byte也就浪費(fèi)掉了。那為什么要對(duì)齊?因?yàn)樵趯?duì)齊方式下,CPU 的運(yùn)行效率要快得多(舉個(gè)例子吧,要說(shuō)明的是下面的例子是我從網(wǎng)上摘錄下來(lái)的,不記得出處了。

示例:如下圖,當(dāng)一個(gè)long 型數(shù)(如圖中l(wèi)ong1)在內(nèi)存中的位置正好與內(nèi)存的字邊界對(duì)齊時(shí),CPU 存取這個(gè)數(shù)只需訪問(wèn)一次內(nèi)存,而當(dāng)一個(gè)long 型數(shù)(如圖中的long2)在內(nèi)存中的位置跨越了字邊界時(shí),CPU 存取這個(gè)數(shù)就需要多次訪問(wèn)內(nèi)存,如i960cx 訪問(wèn)這樣的數(shù)需讀內(nèi)存三次(一個(gè)BYTE、一個(gè)SHORT、一個(gè)BYTE,由CPU 的微代碼執(zhí)行,對(duì)軟件透明),所以對(duì)齊方式下CPU 的運(yùn)行效率明顯快多了。

1       8       16      24      32  

------- ------- ------- ---------

| long1 | long1 | long1 | long1 |

------- ------- ------- ---------

|        |        |         | long2 |

------- ------- ------- ---------

| long2 | long2 | long2 |        |

------- ------- ------- ---------

| ....)。好像扯得有點(diǎn)遠(yuǎn)來(lái),但是有助于對(duì)_INTSIZEOF(n)的理解。位操作對(duì)于我來(lái)說(shuō)是玄的東東。單個(gè)位運(yùn)算還應(yīng)付得來(lái),而這樣一個(gè)表達(dá)式擺在面前就暈了。怎么辦?菜鳥(niǎo)自有菜的辦法。(待續(xù))


Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=14721

---------------------------------------------------------------------------------------------------------------------

C語(yǔ)言中的可變參數(shù)函數(shù)    CSDN Blog推出文章指數(shù)概念,文章指數(shù)是對(duì)Blog文章綜合評(píng)分后推算出的,綜合評(píng)分項(xiàng)分別是該文章的點(diǎn)擊量,回復(fù)次數(shù),被網(wǎng)摘收錄數(shù)量,文章長(zhǎng)度和文章類型;滿分100,每月更新一次。

第一篇

C語(yǔ)言編程中有時(shí)會(huì)遇到一些參數(shù)個(gè)數(shù)可變的函數(shù),例如printf()函數(shù),其函數(shù)原型為:

int printf( const char* format, ...);

它除了有一個(gè)參數(shù)format固定以外,后面跟的參數(shù)的個(gè)數(shù)和類型是可變的(用三個(gè)點(diǎn)“…”做參數(shù)占位符),實(shí)際調(diào)用時(shí)可以有以下的形式:

printf("%d",i);
printf("%s",s);
printf("the number is %d ,string is:%s", i, s);  

一個(gè)簡(jiǎn)單的可變參數(shù)的C函數(shù)

     先看例子程序。該函數(shù)至少有一個(gè)整數(shù)參數(shù),其后占位符…,表示后面參數(shù)的個(gè)數(shù)不定。在這個(gè)例子里,所有的輸入?yún)?shù)必須都是整數(shù),函數(shù)的功能只是打印所有參數(shù)的值。函數(shù)代碼如下:

//示例代碼1:可變參數(shù)函數(shù)的使用
#include "stdio.h"
#include "stdarg.h"
void simple_va_fun(int start, ...)
{
    va_list arg_ptr;
    int nArgValue =start;
    int nArgCout="0"; //可變參數(shù)的數(shù)目
    va_start(arg_ptr,start); //以固定參數(shù)的地址為起點(diǎn)確定變參的內(nèi)存起始地址。
    do
    {
        ++nArgCout;
        printf("the %d th arg: %d",nArgCout,nArgValue); //輸出各參數(shù)的值
        nArgValue = va_arg(arg_ptr,int); //得到下一個(gè)可變參數(shù)的值
    } while(nArgValue != -1);              
    return;
}
int main(int argc, char* argv[])
{
    simple_va_fun(100,-1);
    simple_va_fun(100,200,-1);
    return 0;
}

下面解釋一下這些代碼。從這個(gè)函數(shù)的實(shí)現(xiàn)可以看到,我們使用可變參數(shù)應(yīng)該有以下步驟:

⑴由于在程序中將用到以下這些宏:
void va_start( va_list arg_ptr, prev_param );
type va_arg( va_list arg_ptr, type );
void va_end( va_list arg_ptr );
va在這里是variable-argument(可變參數(shù))的意思。
這些宏定義在stdarg.h中,所以用到可變參數(shù)的程序應(yīng)該包含這個(gè)頭文件。

⑵函數(shù)里首先定義一個(gè)va_list型的變量,這里是arg_ptr,這個(gè)變量是存儲(chǔ)參數(shù)地址的指針.因?yàn)榈玫絽?shù)的地址之后,再結(jié)合參數(shù)的類型,才能得到參數(shù)的值。

⑶然后用va_start宏初始化⑵中定義的變量arg_ptr,這個(gè)宏的第二個(gè)參數(shù)是可變參數(shù)列表的前一個(gè)參數(shù),即最后一個(gè)固定參數(shù)。

⑷然后依次用va_arg宏使arg_ptr返回可變參數(shù)的地址,得到這個(gè)地址之后,結(jié)合參數(shù)的類型,就可以得到參數(shù)的值。

⑸設(shè)定結(jié)束條件,這里的條件就是判斷參數(shù)值是否為-1。注意被調(diào)的函數(shù)在調(diào)用時(shí)是不知道可變參數(shù)的正確數(shù)目的,程序員必須自己在代碼中指明結(jié)束條件。至于為什么它不會(huì)知道參數(shù)的數(shù)目,在看完這幾個(gè)宏的內(nèi)部實(shí)現(xiàn)機(jī)制后,自然就會(huì)明白。

第二篇

C語(yǔ)言之可變參數(shù)問(wèn)題



C語(yǔ)言中有一種長(zhǎng)度不確定的參數(shù),形如:"…",它主要用在參數(shù)個(gè)數(shù)不確定的函數(shù)中,我們最容易想到的例子是printf函數(shù)。

  原型:

  int printf( const char *format [, argument]... );

  使用例:

  printf("Enjoy yourself everyday!\n");

  printf("The value is %d!\n", value);

  這種可變參數(shù)可以說(shuō)是C語(yǔ)言一個(gè)比較難理解的部分,這里會(huì)由幾個(gè)問(wèn)題引發(fā)一些對(duì)它的分析。

  注意:在C++中有函數(shù)重載(overload)可以用來(lái)區(qū)別不同函數(shù)參數(shù)的調(diào)用,但它還是不能表示任意數(shù)量的函數(shù)參數(shù)。

  問(wèn)題:printf的實(shí)現(xiàn)

  請(qǐng)問(wèn),如何自己實(shí)現(xiàn)printf函數(shù),如何處理其中的可變參數(shù)問(wèn)題? 答案與分析:

  在標(biāo)準(zhǔn)C語(yǔ)言中定義了一個(gè)頭文件專門(mén)用來(lái)對(duì)付可變參數(shù)列表,它包含了一組宏,和一個(gè)va_list的typedef聲明。一個(gè)典型實(shí)現(xiàn)如下:

  typedef char* va_list;

  #define va_start(list) list = (char*)&va_alist

  #define va_end(list)

  #define va_arg(list, mode)\

  ((mode*) (list += sizeof(mode)))[-1]

  自己實(shí)現(xiàn)printf:

  #include

  int printf(char* format, …)

  {

  va_list ap;

  va_start(ap, format);

  int n = vprintf(format, ap);

  va_end(ap);

  return n;

  }

  問(wèn)題:運(yùn)行時(shí)才確定的參數(shù)

  有沒(méi)有辦法寫(xiě)一個(gè)函數(shù),這個(gè)函數(shù)參數(shù)的具體形式可以在運(yùn)行時(shí)才確定?

  答案與分析:

  目前沒(méi)有"正規(guī)"的解決辦法,不過(guò)獨(dú)門(mén)偏方倒是有一個(gè),因?yàn)橛幸粋€(gè)函數(shù)已經(jīng)給我們做出了這方面的榜樣,那就是main(),它的原型是:

  int main(int argc,char *argv[]);
函數(shù)的參數(shù)是argc和argv。

  深入想一下,"只能在運(yùn)行時(shí)確定參數(shù)形式",也就是說(shuō)你沒(méi)辦法從聲明中看到所接受的參數(shù),也即是參數(shù)根本就沒(méi)有固定的形式。常用的辦法是你可以通過(guò)定義一個(gè)void *類型的參數(shù),用它來(lái)指向?qū)嶋H的參數(shù)區(qū),然后在函數(shù)中根據(jù)根據(jù)需要任意解釋它們的含義。這就是main函數(shù)中argv的含義,而argc,則用來(lái)表明實(shí)際的參數(shù)個(gè)數(shù),這為我們使用提供了進(jìn)一步的方便,當(dāng)然,這個(gè)參數(shù)不是必需的。

  雖然參數(shù)沒(méi)有固定形式,但我們必然要在函數(shù)中解析參數(shù)的意義,因此,理所當(dāng)然會(huì)有一個(gè)要求,就是調(diào)用者和被調(diào)者之間要對(duì)參數(shù)區(qū)內(nèi)容的格式,大小,有效性等所有方面達(dá)成一致,否則南轅北轍各說(shuō)各話就慘了。

  問(wèn)題:可變長(zhǎng)參數(shù)的傳遞

  有時(shí)候,需要編寫(xiě)一個(gè)函數(shù),將它的可變長(zhǎng)參數(shù)直接傳遞給另外的函數(shù),請(qǐng)問(wèn),這個(gè)要求能否實(shí)現(xiàn)?

  答案與分析:

  目前,你尚無(wú)辦法直接做到這一點(diǎn),但是我們可以迂回前進(jìn),首先,我們定義被調(diào)用函數(shù)的參數(shù)為va_list類型,同時(shí)在調(diào)用函數(shù)中將可變長(zhǎng)參數(shù)列表轉(zhuǎn)換為va_list,這樣就可以進(jìn)行變長(zhǎng)參數(shù)的傳遞了。看如下所示:

  void subfunc (char *fmt, va_list argp)

  {

  ...

  arg = va_arg (fmt, argp); /* 從argp中逐一取出所要的參數(shù) */

  ...

  }

  void mainfunc (char *fmt, ...)

  {

  va_list argp;

  va_start (argp, fmt); /* 將可變長(zhǎng)參數(shù)轉(zhuǎn)換為va_list */

  subfunc (fmt, argp); /* 將va_list傳遞給子函數(shù) */

  va_end (argp);

  ...

  }

  問(wèn)題:可變長(zhǎng)參數(shù)中類型為函數(shù)指針

  我想使用va_arg來(lái)提取出可變長(zhǎng)參數(shù)中類型為函數(shù)指針的參數(shù),結(jié)果卻總是不正確,為什么?

  答案與分析:

  這個(gè)與va_arg的實(shí)現(xiàn)有關(guān)。一個(gè)簡(jiǎn)單的、演示版的va_arg實(shí)現(xiàn)如下:

  #define va_arg(argp, type) \

  (*(type *)(((argp) += sizeof(type)) - sizeof(type)))

  其中,argp的類型是char *。

  如果你想用va_arg從可變參數(shù)列表中提取出函數(shù)指針類型的參數(shù),例如

  int (*)(),則va_arg(argp, int (*)())被擴(kuò)展為:

  (*(int (*)() *)(((argp) += sizeof (int (*)())) -sizeof (int (*)())))

  顯然,(int (*)() *)是無(wú)意義的。

  解決這個(gè)問(wèn)題的辦法是將函數(shù)指針用typedef定義成一個(gè)獨(dú)立的數(shù)據(jù)類型,例如:

  typedef int (*funcptr)();

  這時(shí)候再調(diào)用va_arg(argp, funcptr)將被擴(kuò)展為:

  (* (funcptr *)(((argp) += sizeof (funcptr)) - sizeof (funcptr)))

  這樣就可以通過(guò)編譯檢查了。

  問(wèn)題:可變長(zhǎng)參數(shù)的獲取

  有這樣一個(gè)具有可變長(zhǎng)參數(shù)的函數(shù),其中有下列代碼用來(lái)獲取類型為float的實(shí)參:

  va_arg (argp, float);

  這樣做可以嗎?

  答案與分析:

  不可以。在可變長(zhǎng)參數(shù)中,應(yīng)用的是"加寬"原則。也就是float類型被擴(kuò)展成double;char, short被擴(kuò)展成int。因此,如果你要去可變長(zhǎng)參數(shù)列表中原來(lái)為float類型的參數(shù),需要用va_arg(argp, double)。對(duì)char和short類型的則用va_arg(argp, int)。

  問(wèn)題:定義可變長(zhǎng)參數(shù)的一個(gè)限制

  為什么我的編譯器不允許我定義如下的函數(shù),也就是可變長(zhǎng)參數(shù),但是沒(méi)有任何的固定參數(shù)?

  int f (...)

  {

  ...

  }

  答案與分析:

  不可以。這是ANSI C 所要求的,你至少得定義一個(gè)固定參數(shù)。

  這個(gè)參數(shù)將被傳遞給va_start(),然后用va_arg()和va_end()來(lái)確定所有實(shí)際調(diào)用時(shí)可變長(zhǎng)參數(shù)的類型和值。---------------------------------------------------------------------------------------------------------------------
如何判別可變參數(shù)函數(shù)的參數(shù)類型?

函數(shù)形式如下:
void   fun(char*   str,...)
{
      ......
}

若傳的參數(shù)個(gè)數(shù)大于1,如何判別第2個(gè)以后傳參的參數(shù)類型???
最好有源碼說(shuō)明!


沒(méi)辦法判斷的


如樓上所說(shuō),例如printf( "%d%c%s ",   ....)是通過(guò)格式串中的%d,   %c,   %s來(lái)確定后面參數(shù)的類型,其實(shí)你也可以參考這種方法來(lái)判斷不定參數(shù)的類型.


無(wú)法判斷。可變參數(shù)實(shí)現(xiàn)主要通過(guò)三個(gè)宏實(shí)現(xiàn):va_start,   va_arg,   va_end。


六、 擴(kuò)展與思考

個(gè)數(shù)可變參數(shù)在聲明時(shí)只需"..."即可;但是,我們?cè)诮邮苓@些參數(shù)時(shí)不能"..."。va函數(shù)實(shí)現(xiàn)的關(guān)鍵就是如何得到參數(shù)列表中可選參數(shù),包括參數(shù)的值和類型。以上的所有實(shí)現(xiàn)都是基于來(lái)自stdarg.h的va_xxx的宏定義。 <思考>能不能不借助于va_xxx,自己實(shí)現(xiàn)VA呢?,我想到的方法是匯編。在C中,我們當(dāng)然就用C的嵌入?yún)R編來(lái)實(shí)現(xiàn),這應(yīng)該是可以做得到的。至于能做到什么程度,穩(wěn)定性和效率怎么樣,主要要看你對(duì)內(nèi)存和指針的控制了。

參考資料

1.IEEE和OpenGroup聯(lián)合開(kāi)發(fā)的Single Unix specification Ver3;BR>
2.Linux man手冊(cè);

3.x86匯編,還有一些安全編碼方面的資料。

---------------------------------------------------------------------------------------------------------------------
[轉(zhuǎn)帖]對(duì)C/C++可變參數(shù)表的深層探索

C/C++語(yǔ)言有一個(gè)不同于其它語(yǔ)言的特性,即其支持可變參數(shù),典型的函數(shù)如printf、scanf等可以接受數(shù)量不定的參數(shù)。如:
  printf ( "I love you" );
  printf ( "%d", a );
  printf ( "%d,%d", a, b );
  第一、二、三個(gè)printf分別接受1、2、3個(gè)參數(shù),讓我們看看printf函數(shù)的原型:
  int printf ( const char *format, ... );
  從函數(shù)原型可以看出,其除了接收一個(gè)固定的參數(shù)format以外,后面的參數(shù)用"…"表示。在C/C++語(yǔ)言中,"…"表示可以接受不定數(shù)量的參數(shù),理論上來(lái)講,可以是0或0以上的n個(gè)參數(shù)。
  本文將對(duì)C/C++可變參數(shù)表的使用方法及C/C++支持可變參數(shù)表的深層機(jī)理進(jìn)行探索。

  一. 可變參數(shù)表的用法
  1、相關(guān)宏
  標(biāo)準(zhǔn)C/C++包含頭文件stdarg.h,該頭文件中定義了如下三個(gè)宏:
void va_start ( va_list arg_ptr, prev_param ); /* ANSI version */
type va_arg ( va_list arg_ptr, type );
void va_end ( va_list arg_ptr );
  在這些宏中,va就是variable argument(可變參數(shù))的意思;arg_ptr是指向可變參數(shù)表的指針;prev_param則指可變參數(shù)表的前一個(gè)固定參數(shù);type為可變參數(shù)的類型。va_list也是一個(gè)宏,其定義為typedef char * va_list,實(shí)質(zhì)上是一 char型指針。char型指針的特點(diǎn)是++、--操作對(duì)其作用的結(jié)果是增1和減1(因?yàn)閟izeof(char)為1),與之不同的是int等其它類型指針的++、--操作對(duì)其作用的結(jié)果是增sizeof(type)或減sizeof(type),而且sizeof (type)大于1。
  通過(guò)va_start宏我們可以取得可變參數(shù)表的首指針,這個(gè)宏的定義為:
#define va_start ( ap, v ) ( ap = (va_list)&v + _INTSIZEOF(v) )
  顯而易見(jiàn),其含義為將最后那個(gè)固定參數(shù)的地址加上可變參數(shù)對(duì)其的偏移后賦值給ap,這樣ap就是可變參數(shù)表的首地址。其中的_INTSIZEOF宏定義為:
#define _INTSIZEOF(n) ((sizeof ( n ) + sizeof ( int ) - 1 ) & ~( sizeof( int ) - 1 ) )
  va_arg宏的意思則指取出當(dāng)前arg_ptr所指的可變參數(shù)并將ap指針指向下一可變參數(shù),其原型為:
#define va_arg(list, mode) ((mode *)(list =(char *) ((((int)list + (__builtin_alignof(mode)<=4?3:7)) &(__builtin_alignof(mode)<=4?-4:-8))+sizeof(mode))))[-1]
  對(duì)這個(gè)宏的具體含義我們將在后面深入討論。
  而va_end宏被用來(lái)結(jié)束可變參數(shù)的獲取,其定義為:
#define va_end ( list )
  可以看出,va_end ( list )實(shí)際上被定義為空,沒(méi)有任何真實(shí)對(duì)應(yīng)的代碼,用于代碼對(duì)稱,與va_start對(duì)應(yīng);另外,它還可能發(fā)揮代碼的"自注釋"作用。所謂代碼的"自注釋",指的是代碼能自己注釋自己。
  下面我們以具體的例子來(lái)說(shuō)明以上三個(gè)宏的使用方法。
  2、一個(gè)簡(jiǎn)單的例子
  #include <stdarg.h>
  /* 函數(shù)名:max
  * 功能:返回n個(gè)整數(shù)中的最大值
  * 參數(shù):num:整數(shù)的個(gè)數(shù) ...:num個(gè)輸入的整數(shù)
  * 返回值:求得的最大整數(shù)
  */
  int max ( int num, ... )
  {
   int m = -0x7FFFFFFF; /* 32系統(tǒng)中最小的整數(shù) */
   va_list ap;
   va_start ( ap, num );
   for ( int i= 0; i< num; i++ )
   {
    int t = va_arg (ap, int);
    if ( t > m )
    {
     m = t;
    }
   }
   va_end (ap);
   return m;
  }
  /* 主函數(shù)調(diào)用max */
  int main ( int argc, char* argv[] )
  {
   int n = max ( 5, 5, 6 ,3 ,8 ,5); /* 求5個(gè)整數(shù)中的最大值 */
   cout << n;
   return 0;
  }
  函數(shù)max中首先定義了可變參數(shù)表指針ap,而后通過(guò)va_start ( ap, num )取得了參數(shù)表首地址(賦給了ap),其后的for循環(huán)則用來(lái)遍歷可變參數(shù)表。這種遍歷方式與我們?cè)跀?shù)據(jù)結(jié)構(gòu)教材中經(jīng)常看到的遍歷方式是類似的。
  函數(shù)max看起來(lái)簡(jiǎn)潔明了,但是實(shí)際上printf的實(shí)現(xiàn)卻遠(yuǎn)比這復(fù)雜。max函數(shù)之所以看起來(lái)簡(jiǎn)單,是因?yàn)椋?br>  (1) max函數(shù)可變參數(shù)表的長(zhǎng)度是已知的,通過(guò)num參數(shù)傳入;
  (2) max函數(shù)可變參數(shù)表中參數(shù)的類型是已知的,都為int型。
  而printf函數(shù)則沒(méi)有這么幸運(yùn)。首先,printf函數(shù)可變參數(shù)的個(gè)數(shù)不能輕易的得到,而可變參數(shù)的類型也不是固定的,需由格式字符串進(jìn)行識(shí)別(由%f、%d、%s等確定),因此則涉及到可變參數(shù)表的更復(fù)雜應(yīng)用。
  下面我們以實(shí)例來(lái)分析可變參數(shù)表的高級(jí)應(yīng)用。

  二. 高級(jí)應(yīng)用
  下面這個(gè)程序是我們?yōu)槟城度胧较到y(tǒng)(該系統(tǒng)中CPU的字長(zhǎng)為16位)編寫(xiě)的在屏幕上顯示格式字符串的函數(shù)DrawText,它的用法類似于 int printf ( const char *format, ... )函數(shù),但其輸出的目標(biāo)為嵌入式系統(tǒng)的液晶顯示屏幕(LED)。
  ///////////////////////////////////////////////////////////////////////////////
  // 函數(shù)名稱: DrawText
  // 功能說(shuō)明: 在顯示屏上繪制文字
  // 參數(shù)說(shuō)明: xPos ---橫坐標(biāo)的位置 [0 .. 30]
  // yPos ---縱坐標(biāo)的位置 [0 .. 64]
  // ... 可以同數(shù)字一起顯示,需設(shè)置標(biāo)志(%d、%l、%x、%s)
  ///////////////////////////////////////////////////////////////////////////////
  extern void DrawText ( BYTE xPos, BYTE yPos, LPBYTE lpStr, ... )
  {
   BYTE lpData[100]; //緩沖區(qū)
   BYTE byIndex;
   BYTE byLen;
   DWORD dwTemp;
   WORD wTemp;
   int i;
   va_list lpParam;
   memset( lpData, 0, 100);
   byLen = strlen( lpStr );
   byIndex = 0;
   va_start ( lpParam, lpStr );
   for ( i = 0; i < byLen; i++ )
   {
    if( lpStr[i] != ’%’ ) //不是格式符開(kāi)始
    {
     lpData[byIndex++] = lpStr[i];
    }
    else
    {
     switch (lpStr[i+1])
     {
      //整型
      case ’d’:
      case ’D’:
       wTemp = va_arg ( lpParam, int );
       byIndex += IntToStr( lpData+byIndex, (DWORD)wTemp );
       i++;
       break;
      //長(zhǎng)整型
      case ’l’:
      case ’L’:
       dwTemp = va_arg ( lpParam, long );
       byIndex += IntToStr ( lpData+byIndex, (DWORD)dwTemp );
       i++;
       break;
      //16進(jìn)制(長(zhǎng)整型)
      case ’x’:
      case ’X’:
       dwTemp = va_arg ( lpParam, long );
       byIndex += HexToStr ( lpData+byIndex, (DWORD)dwTemp );
       i++;
       break;
      default:
       lpData[byIndex++] = lpStr[i];
       break;
     }
    }
   }
   va_end ( lpParam );
   lpData[byIndex] = ’#CONTENT#’;
   DisplayString ( xPos, yPos, lpData, TRUE); //在屏幕上顯示字符串lpData
  }
  在這個(gè)函數(shù)中,需通過(guò)對(duì)傳入的格式字符串(首地址為lpStr)進(jìn)行識(shí)別來(lái)獲知可變參數(shù)個(gè)數(shù)及各個(gè)可變參數(shù)的類型,具體實(shí)現(xiàn)體現(xiàn)在for循環(huán)中。譬如,在識(shí)別為%d后,做的是va_arg ( lpParam, int ),而獲知為%l和%x后則進(jìn)行的是va_arg ( lpParam, long )。格式字符串識(shí)別完成后,可變參數(shù)也就處理完了。
  在項(xiàng)目的最初,我們一直苦于不能找到一個(gè)好的辦法來(lái)混合輸出字符串和數(shù)字,我們采用了分別顯示數(shù)字和字符串的方法,并分別指定坐標(biāo),程序條理被破壞。而且,在混合顯示的時(shí)候,要給各類數(shù)據(jù)分別人工計(jì)算坐標(biāo),我們感覺(jué)頭疼不已。以前的函數(shù)為:
  //顯示字符串
  showString ( BYTE xPos, BYTE yPos, LPBYTE lpStr )
  //顯示數(shù)字
  showNum ( BYTE xPos, BYTE yPos, int num )
  //以16進(jìn)制方式顯示數(shù)字
  showHexNum ( BYTE xPos, BYTE yPos, int num )
  最終,我們用DrawText ( BYTE xPos, BYTE yPos, LPBYTE lpStr, ... )函數(shù)代替了原先所有的輸出函數(shù),程序得到了簡(jiǎn)化。就這樣,兄弟們用得爽翻了。

  三. 運(yùn)行機(jī)制探索
  通過(guò)第2節(jié)我們學(xué)會(huì)了可變參數(shù)表的使用方法,相信喜歡拋根問(wèn)底的讀者還不甘心,必然想知道如下問(wèn)題:
  (1)為什么按照第2節(jié)的做法就可以獲得可變參數(shù)并對(duì)其進(jìn)行操作?
  (2)C/C++在底層究竟是依靠什么來(lái)對(duì)這一語(yǔ)法進(jìn)行支持的,為什么其它語(yǔ)言就不能提供可變參數(shù)表呢?
  我們帶著這些疑問(wèn)來(lái)一步步進(jìn)行摸索。
  3.1 調(diào)用機(jī)制反匯編
  反匯編是研究語(yǔ)法深層特性的終極良策,先來(lái)看看2.2節(jié)例子中主函數(shù)進(jìn)行max ( 5, 5, 6 ,3 ,8 ,5)調(diào)用時(shí)的反匯編:
  1. 004010C8 push 5
  2. 004010CA push 8
  3. 004010CC push 3
  4. 004010CE push 6
  5. 004010D0 push 5
  6. 004010D2 push 5
  7. 004010D4 call @ILT+5(max) (0040100a)
  從上述反匯編代碼中我們可以看出,C/C++函數(shù)調(diào)用的過(guò)程中:
  第一步:將參數(shù)從右向左入棧(第1~6行);
  第二步:調(diào)用call指令進(jìn)行跳轉(zhuǎn)(第7行)。
  這兩步包含了深刻的含義,它說(shuō)明C/C++默認(rèn)的調(diào)用方式為由調(diào)用者管理參數(shù)入棧的操作,且入棧的順序?yàn)閺挠抑磷螅@種調(diào)用方式稱為_(kāi)cdecl調(diào)用。x86系統(tǒng)的入棧方向?yàn)閺母叩刂返降偷刂罚实?至n個(gè)參數(shù)被放在了地址遞增的堆棧內(nèi)。在被調(diào)用函數(shù)內(nèi)部,讀取這些堆棧的內(nèi)容就可獲得各個(gè)參數(shù)的值,讓我們反匯編到max函數(shù)的內(nèi)部:
  int max ( int num, ...)
  {
  1. 00401020 push ebp
  2. 00401021 mov ebp,esp
  3. 00401023 sub esp,50h
  4. 00401026 push ebx
  5. 00401027 push esi
  6. 00401028 push edi
  7. 00401029 lea edi,[ebp-50h]
  8. 0040102C mov ecx,14h
  9. 00401031 mov eax,0CCCCCCCCh
  10. 00401036 rep stos dword ptr [edi]
  va_list ap;
  int m = -0x7FFFFFFF; /* 32系統(tǒng)中最小的整數(shù) */
  11. 00401038 mov dword ptr [ebp-8],80000001h
  va_start ( ap, num );
  12. 0040103F lea eax,[ebp+0Ch]
  13. 00401042 mov dword ptr [ebp-4],eax
  for ( int i= 0; i< num; i++ )
  14. 00401045 mov dword ptr [ebp-0Ch],0
  15. 0040104C jmp max+37h (00401057)
  16. 0040104E mov ecx,dword ptr [ebp-0Ch]
  17. 00401051 add ecx,1
  18. 00401054 mov dword ptr [ebp-0Ch],ecx
  19. 00401057 mov edx,dword ptr [ebp-0Ch]
  20. 0040105A cmp edx,dword ptr [ebp+8]
  21. 0040105D jge max+61h (00401081)
  {
   int t= va_arg (ap, int);
   22. 0040105F mov eax,dword ptr [ebp-4]
   23. 00401062 add eax,4
   24. 00401065 mov dword ptr [ebp-4],eax
   25. 00401068 mov ecx,dword ptr [ebp-4]
   26. 0040106B mov edx,dword ptr [ecx-4]
   27. 0040106E mov dword ptr [t],edx
   if ( t > m )
    28. 00401071 mov eax,dword ptr [t]
    29. 00401074 cmp eax,dword ptr [ebp-8]
    30. 00401077 jle max+5Fh (0040107f)
    m = t;
    31. 00401079 mov ecx,dword ptr [t]
    32. 0040107C mov dword ptr [ebp-8],ecx
   }
   33. 0040107F jmp max+2Eh (0040104e)
   va_end (ap);
   34. 00401081 mov dword ptr [ebp-4],0
   return m;
   35. 00401088 mov eax,dword ptr [ebp-8]
  }
  36. 0040108B pop edi
  37. 0040108C pop esi
  38. 0040108D pop ebx
  39. 0040108E mov esp,ebp
  40. 00401090 pop ebp
  41. 00401091 ret
  分析上述反匯編代碼,對(duì)于一個(gè)真正的程序員而言,將是一種很大的享受;而對(duì)于初學(xué)者,也將使其受益良多。所以請(qǐng)一定要賴著頭皮認(rèn)真研究,千萬(wàn)不要被嚇倒!
  行1~10進(jìn)行執(zhí)行函數(shù)內(nèi)代碼的準(zhǔn)備工作,保存現(xiàn)場(chǎng)。第2行對(duì)堆棧進(jìn)行移動(dòng);第3行則意味著max函數(shù)為其內(nèi)部局部變量準(zhǔn)備的堆棧空間為50h字節(jié);第11行表示把變量n的內(nèi)存空間安排在了函數(shù)內(nèi)部局部棧底減8的位置(占用4個(gè)字節(jié))。
  第12~13行非常關(guān)鍵,對(duì)應(yīng)著va_start ( ap, num ),這兩行將第一個(gè)可變參數(shù)的地址賦值給了指針ap。另外,從第12行可以看出num的地址為ebp+0Ch;從第13行可以看出ap被分配在函數(shù)內(nèi)部局部棧底減4的位置上(占用4個(gè)字節(jié))。
  第22~27行最為關(guān)鍵,對(duì)應(yīng)著va_arg (ap, int)。其中,22~24行的作用為將ap指向下一可變參數(shù)(可變參數(shù)的地址間隔為4個(gè)字節(jié),從add eax,4可以看出);25~27行則取當(dāng)前可變參數(shù)的值賦給變量t。這段反匯編很奇怪,它先移動(dòng)可變參數(shù)指針,再在賦值指令里面回過(guò)頭來(lái)取先前的參數(shù)值賦給t(從mov edx,dword ptr [ecx-4]語(yǔ)句可以看出)。Visual C++同學(xué)玩得有意思,不知道碰見(jiàn)同樣的情況Visual Basic等其它同學(xué)怎么玩?
  第36~41行恢復(fù)現(xiàn)場(chǎng)和堆棧地址,執(zhí)行函數(shù)返回操作。
  痛苦的反匯編之旅差不多結(jié)束了,看了這段反匯編我們總算弄明白了可變參數(shù)的存放位置以及它們被讀取的方式,頓覺(jué)全省輕松!
  2、特殊的調(diào)用約定
  除此之外,我們需要了解C/C++函數(shù)調(diào)用對(duì)參數(shù)占用空間的一些特殊約定,因?yàn)樵赺cdecl調(diào)用協(xié)議中,有些變量類型是按照其它變量的尺寸入棧的。
  例如,字符型變量將被自動(dòng)擴(kuò)展為一個(gè)字的空間,因?yàn)槿霔2僮麽槍?duì)的是一個(gè)字。
  參數(shù)n實(shí)際占用的空間為( ( sizeof(n) + sizeof(int) - 1 ) & ~( sizeof(int) - 1 ) ),這就是第2.1節(jié)_INTSIZEOF(v)宏的來(lái)歷!
  既然如此,前面給出的va_arg ( list, mode )宏為什么玩這么大的飛機(jī)就很清楚了。這個(gè)問(wèn)題就留個(gè)讀者您來(lái)分析.



http://wp1314.ycool.com/post.3001515.html

posted @ 2010-06-17 23:52 Brandon 閱讀(1486) | 評(píng)論 (0)編輯 收藏

c++中string的一些轉(zhuǎn)換

這是我上次從這里看到的把它給保存了下來(lái),希望對(duì)你有用。 
1. c++中string到int的轉(zhuǎn)換 
1) 在C標(biāo)準(zhǔn)庫(kù)里面,使用atoi: 

#include <cstdlib> 
#include <string> 

std::string text = "152"; 
int number = std::atoi( text.c_str() ); 
if (errno == ERANGE) //可能是std::errno 

//number可能由于過(guò)大或過(guò)小而不能完全存儲(chǔ) 

else if (errno == ????) 
//可能是EINVAL 

//不能轉(zhuǎn)換成一個(gè)數(shù)字 


2) 在C++標(biāo)準(zhǔn)庫(kù)里面,使用stringstream:(stringstream 可以用于各種數(shù)據(jù)類型之間的轉(zhuǎn)換) 

#include <sstream> 
#include <string> 

std::string text = "152"; 
int number; 
std::stringstream ss; 


ss < < text;//可以是其他數(shù)據(jù)類型 
ss >> number; //string -> int 
if (! ss.good()) 

//錯(cuò)誤發(fā)生 



ss < < number;// int->string 
string str = ss.str(); 
if (! ss.good()) 

//錯(cuò)誤發(fā)生 


3) 在Boost庫(kù)里面,使用lexical_cast: 

#include <boost/lexical_cast.hpp> 
#include <string> 

try 

std::string text = "152"; 
int number = boost::lexical_cast < int >( text ); 

catch( const boost::bad_lexical_cast & ) 

//轉(zhuǎn)換失敗 
}                      

2.string 轉(zhuǎn) CString 
CString.format(”%s”, string.c_str()); 
用c_str()確實(shí)比data()要好; 


3.char 轉(zhuǎn) CString 
CString.format(”%s”, char*); 

4.char 轉(zhuǎn) string 
string s(char *); 
只能初始化,在不是初始化的地方最好還是用assign(). 


5.string 轉(zhuǎn) char * 
char *p = string.c_str(); 

6.CString 轉(zhuǎn) string 
string s(CString.GetBuffer()); 
GetBuffer()后一定要ReleaseBuffer(),否則就沒(méi)有釋放緩沖區(qū)所占的空間. 

7.字符串的內(nèi)容轉(zhuǎn)換為字符數(shù)組和C—string 
(1)  data(),返回沒(méi)有”\0“的字符串?dāng)?shù)組 
(2)  c_str(),返回有”\0“的字符串?dāng)?shù)組 
(3)  copy() 

8.CString與int、char*、char[100]之間的轉(zhuǎn)換 

(1) CString互轉(zhuǎn)int 

將字符轉(zhuǎn)換為整數(shù),可以使用atoi、_atoi64或atol。而將數(shù)字轉(zhuǎn)換為CString變量,可以使用CString的Format函數(shù)。如 
CString s; 
int i = 64; 
s.Format(”%d”, i) 
Format函數(shù)的功能很強(qiáng),值得你研究一下。 

void CStrDlg::OnButton1() 

  CString 
  ss=”1212.12″; 
  int temp=atoi(ss); 
  CString aa; 
  aa.Format(”%d”,temp); 
  AfxMessageBox(”var is ” + aa); 


(2) CString互轉(zhuǎn)char* 

///char * TO cstring 
CString strtest; 
char * charpoint; 
charpoint=”give string a value”; //? 
strtest=charpoint; 

///cstring TO char * 
charpoint=strtest.GetBuffer(strtest.GetLength()); 

(3) 標(biāo)準(zhǔn)C里沒(méi)有string,char *==char []==string, 可以用CString.Format(”%s”,char *)這個(gè)方法來(lái)將char *轉(zhuǎn)成CString。 
    要把CString轉(zhuǎn)成char *,用操作符(LPCSTR)CString就可以了。 
    CString轉(zhuǎn)換 char[100] 
  char a[100]; 
  CString str(”aaaaaa”); 
  strncpy(a,(LPCTSTR)str,sizeof(a)); 

posted @ 2009-05-31 12:38 Brandon 閱讀(465) | 評(píng)論 (0)編輯 收藏

lua的隨機(jī)數(shù)問(wèn)題

http://dev.csdn.net/author/yanjun_1982/b682d53ae78846a19eb0b7751a250750.html     

   也許很多人會(huì)奇怪為什么使用LUA的時(shí)候,第一個(gè)隨機(jī)數(shù)總是固定,而且常常是最小的那個(gè)值,下面我就簡(jiǎn)要的說(shuō)明一下吧,說(shuō)得不好,還請(qǐng)諒解。我現(xiàn)在使用的4.0版本的LUA,看的代碼是5.0的,呵呵

        LUA4.0版本中的自帶函數(shù)庫(kù)中有兩個(gè)關(guān)于隨機(jī)數(shù)的函數(shù),一個(gè)是random,一個(gè)是randomseed。random有兩個(gè)參數(shù),用來(lái)設(shè)置隨機(jī)數(shù)的范圍,比如random(1,100)設(shè)置隨機(jī)數(shù)的范圍為1至100之間。由于C中所產(chǎn)生的隨機(jī)序列是固定的,并且第一個(gè)隨機(jī)數(shù)比較小,只有41。LUA重新設(shè)計(jì)了random函數(shù),使得它可以產(chǎn)生范圍固定的隨機(jī)數(shù),但由于LUA的random只是封裝了C的rand函數(shù),使得random函數(shù)也有一定的缺陷,那就是如果random的兩個(gè)輸入?yún)?shù)的值相差很小的時(shí)候,那么隨機(jī)序列的第一個(gè)隨機(jī)數(shù)就會(huì)和第一個(gè)輸入?yún)?shù)很接近,比如第一次調(diào)用random(1,100)的時(shí)候,返回值肯定是1,只有相差大于799時(shí),如random(1,800)第一次調(diào)用才會(huì)返回2,也是很接近1。
        由于這個(gè)原因,為了實(shí)現(xiàn)真正的隨機(jī),那么第一次就不能讓玩家調(diào)用random函數(shù),不然玩家就可以獲得一些低概率的東西了。比如if random(1,100) == 1 then ...... do,看起來(lái)是1%的的概率,但是第一次執(zhí)行的時(shí)候是100%成立的,存在一定的隱患。解決這個(gè)問(wèn)題的方法有兩個(gè),一就是第一次random函數(shù)不能讓玩家執(zhí)行,二就是使用randomseed先設(shè)一個(gè)隨機(jī)種子。對(duì)于第一種方法,可能還是有一定的風(fēng)險(xiǎn),畢竟隨機(jī)序列還是固定的,玩家第一次調(diào)用random的時(shí)候還是得到有規(guī)律的返回值。第二種方法比較安全,在服務(wù)器啟動(dòng)的時(shí)候設(shè)置一個(gè)隨機(jī)種子,讓系統(tǒng)產(chǎn)生的隨機(jī)序列不相同,但使用randomseed的時(shí)候也還要注意一個(gè)問(wèn)題,那就是做種子的數(shù)要足夠的大,大于10000就行了。不然randomseed所產(chǎn)生的隨機(jī)序列的第一個(gè)值還是很小。原因是randomseed是直接封裝了C的srand,如果種子的值太小,那么srand所產(chǎn)生的序列和默認(rèn)序列(srand(1)所產(chǎn)生的序列)是相差不大的,序列的第一個(gè)值還是很小。
        因此,只要在服務(wù)器啟動(dòng)的時(shí)候調(diào)用一下randomseed(GetTime())就可以解決這個(gè)問(wèn)題了。
        還要補(bǔ)充一下,LUA中產(chǎn)生隨機(jī)數(shù)的算法還是有一些問(wèn)題,比如執(zhí)行random(1,3276700),它返回的值最后兩位必為0。這是由LUA本身的隨機(jī)函數(shù)算法決定的。
        還是簡(jiǎn)要介紹一下LUA中random函數(shù)的實(shí)現(xiàn)方法吧,主要由源碼中的下面兩行實(shí)現(xiàn):
        lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX;
        lua_pushnumber(L, (int)floor(r*(u-m+1))+m);
        其中m為random函數(shù)的第一個(gè)參數(shù),u為第二個(gè)參數(shù)。由上面的代碼可以看出,如果u-l太小,那么當(dāng)r也很小的時(shí)候,r*(u-m+1)就會(huì)很小(小于1),那么再經(jīng)過(guò)floor運(yùn)算,最經(jīng)結(jié)果就是m。這就可以解釋為什么random產(chǎn)生的第一個(gè)隨機(jī)數(shù)常常會(huì)很接近m。再來(lái)看看當(dāng)m為0,u為327670的時(shí)候會(huì)怎樣。在上面的代碼里,RAND_MAX是一個(gè)宏,它的值是32767,也就是C語(yǔ)言中rand函數(shù)可以返回的最大值(不同的操作系統(tǒng)可能會(huì)有不一樣的最大值)。當(dāng)m為0,u為327670的時(shí)候,那么返回值就是floor(r*(327671)+0),我們?cè)偌僭O(shè)LUA與平臺(tái)無(wú)關(guān)并且rand不會(huì)返回32767(上面用%避免了這個(gè)問(wèn)題),那么r就可以簡(jiǎn)化為rand()/RAND_MAX,代入上式為floor(rand()*327671/32767)+0,就算rand()的返回值是32766,最終的結(jié)果也只有327660.99996......,經(jīng)過(guò)floor運(yùn)算后,最后那位數(shù)必為0。呵呵,我叫這樣的隨機(jī)數(shù)就偽隨機(jī)數(shù)中的偽隨機(jī)數(shù)。實(shí)際上面的公式是不允許化簡(jiǎn)的,即不能簡(jiǎn)單地把r代入r*(u-m+1),至于為什么,呵呵,因?yàn)閞的值并不是rand()/RAND_MAX的值,r是double類型的,所以它只是一個(gè)和rand()/RAND_MAX很接近的數(shù)。 

        引用請(qǐng)注明出處。作者:yanjun_1982   日期:2006年10月11日

posted @ 2009-05-13 10:58 Brandon 閱讀(2096) | 評(píng)論 (0)編輯 收藏

關(guān)于MFC畫(huà)圖的一些總結(jié),MFC (Draw)

     摘要: 轉(zhuǎn)自:http://www.cnblogs.com/volnet/articles/472794.html 首先對(duì)按下鼠標(biāo)的一點(diǎn)進(jìn)行記錄,因此在WM_LBUTTONDOWN添加代碼:void CDrawView::OnLButtonDown(UINT nFlags, CPoint point){     // TODO: ...  閱讀全文

posted @ 2009-04-30 15:07 Brandon 閱讀(5993) | 評(píng)論 (0)編輯 收藏

Lua string一些東西

一,函數(shù)
string.len(s)
string.find(s, sd, [index]) 返回i, j 表示 起始,終了位置索引。
string.sub
string.gsub
string.gfind
string.char
string.byte
string.format

二,字符類和模式修飾符
.      任意字符
%a     字母
%c     控制字符
%d     數(shù)字
%l     小寫(xiě)字母
%p     標(biāo)點(diǎn)字符
%s     空白符
%u     大寫(xiě)字母
%w     字母和數(shù)字
%x     十六進(jìn)制數(shù)字
%z     代表0的字符

模式修飾符有四個(gè):
+      匹配前一字符1次或多次
*      匹配前一字符0次或多次
-      匹配前一字符0次或多次
?      匹配前一字符0次或1次

posted @ 2009-04-29 15:51 Brandon 閱讀(1180) | 評(píng)論 (0)編輯 收藏

郁悶的一個(gè)問(wèn)題

今天碰到個(gè)問(wèn)題:
lua里在一個(gè)串里查找“(”怎么寫(xiě),查找一個(gè)“)”可以寫(xiě)作i,j = string.find(s, ")");
而碰到“(”時(shí)是會(huì)出錯(cuò)的,懷疑一詞法分析的時(shí)候一碰到“(”就壓進(jìn)棧了,然后因?yàn)槔ㄌ?hào)不匹配報(bào)錯(cuò)? 
也不能對(duì)“(”提供轉(zhuǎn)義

posted @ 2009-04-28 18:14 Brandon 閱讀(241) | 評(píng)論 (0)編輯 收藏

泛型算法

拷貝:

copy()
reverse_copy()
rotate_copy()
remove_copy()  拷貝不等于某值的元素到另一個(gè)序列。
remove_copy_if() 拷貝符合條件的到另一個(gè)序列。

填充和生成:
fill()
fill_n() 填充序列中的n個(gè)元素。
generate()為序列中的每個(gè)元素調(diào)用gen()函數(shù)。

排列:
next_permuttion() 后一個(gè)排列。
prev_permutation()

partition() 劃分,將滿足條件的元素移動(dòng)到序列的前面。
stable_partition()

查找和替換:
find()
binary_search() 在一個(gè)已經(jīng)有順序的序列上查找。
find_if()
search() 檢查第二個(gè)序列是否在第一個(gè)序列中出現(xiàn),且順序相同。

刪除:注意必須調(diào)用erase()來(lái)真正刪除
remove()
unique()刪除相鄰重復(fù)元素,最好現(xiàn)排序。

合并序列:
merge()

數(shù)值算法:
accumulate() 對(duì)序列的每個(gè)元素進(jìn)行運(yùn)算后求和。
transform() 也可以對(duì)每個(gè)元素進(jìn)行運(yùn)算。
計(jì)數(shù):
size()總個(gè)數(shù)。
count()等于某值的元素個(gè)數(shù)。

adjacent_difference 序列中的后一個(gè)減前與他相鄰的前一個(gè)得到新的序列。

adiacent_find

 accumlate  iterator 對(duì)標(biāo)志的序列中的元素之和,加到一個(gè)由 init 指定的初始值上。重載的版本不再做加法,而是傳進(jìn)來(lái)的二元操作符被應(yīng)用到元素上。 

adjacent_different :創(chuàng)建一個(gè)新序列,該序列的每個(gè)新值都代表了當(dāng)前元素與上一個(gè)元素的差。重載版本用指定的二元操作計(jì)算相鄰元素的差。 
adjacent_find 
:在 iterator 對(duì)標(biāo)志的元素范圍內(nèi),查找一對(duì)相鄰的重復(fù)元素,如果找到返回一個(gè) ForwardIterator ,指向這對(duì)元素的第一個(gè)元素。否則返回 last 。重載版本使用輸入的二元操作符代替相等的判斷。 
binary_search 
:在有序序列中查找 value ,如果找到返回 true 。重載的版本使用指定的比較函數(shù)對(duì)象或者函數(shù)指針來(lái)判斷相等。 
copy 
:復(fù)制序列。 
copy_backward 
:除了元素以相反的順序被拷貝外,別的和 copy 相同。 
count 
:利用等于操作符,把標(biāo)志范圍類的元素與輸入的值進(jìn)行比較,并返回相等元素的個(gè)數(shù)。 
count_if 
:對(duì)于標(biāo)志范圍類的元素,應(yīng)用輸入的操作符,并返回結(jié)果為 true 的次數(shù)。 
equal 
:如果兩個(gè)序列在范圍內(nèi)的元素都相等,則 equal 返回 true 。重載版本使用輸入的操作符代替了默認(rèn)的等于操作符。 
equal_range 
:返回一對(duì) iterator ,第一個(gè) iterator 表示由 lower_bound 返回的 iterator ,第二個(gè)表示由 upper_bound 返回的 iterator值。 
fill 
:將輸入的值的拷貝賦給范圍內(nèi)的每個(gè)元素。 
fill_n 
:將輸入的值賦值給 first  frist+n 范圍內(nèi)的元素。 
find 
:利用底層元素的等于操作符,對(duì)范圍內(nèi)的元素與輸入的值進(jìn)行比較。當(dāng)匹配時(shí),結(jié)束搜索,返回該元素的一個(gè) InputIterator  
find_if 
:使用輸入的函數(shù)替代了等于操作符執(zhí)行了 find  
find_end 
:在范圍內(nèi)查找“由輸入的另外一個(gè) iterator 對(duì)標(biāo)志的第二個(gè)序列”的最后一次出現(xiàn)。重載版本中使用了用戶輸入的操作符替代等于操作。 
find_first_of 
:在范圍內(nèi)查找“由輸入的另外一個(gè) iterator 對(duì)標(biāo)志的第二個(gè)序列”中的任意一個(gè)元素的第一次出現(xiàn)。重載版本中使用了用戶自定義的操作符。 
for_each 
:依次對(duì)范圍內(nèi)的所有元素執(zhí)行輸入的函數(shù)。 
generate 
:通過(guò)對(duì)輸入的函數(shù) gen 的連續(xù)調(diào)用來(lái)填充指定的范圍。 
generate_n 
:填充 n 個(gè)元素。 
includes 
:判斷 [first1, last1) 的一個(gè)元素是否被包含在另外一個(gè)序列中。使用底層元素的 <= 操作符,重載版本使用用戶輸入的函數(shù)。 
inner_product 
:對(duì)兩個(gè)序列做內(nèi)積 ( 對(duì)應(yīng)的元素相乘,再求和 ) ,并將內(nèi)積加到一個(gè)輸入的的初始值上。重載版本使用了用戶定義的操作。 
inner_merge 
:合并兩個(gè)排過(guò)序的連續(xù)序列,結(jié)果序列覆蓋了兩端范圍,重載版本使用輸入的操作進(jìn)行排序。 
iter_swap 
:交換兩個(gè) ForwardIterator 的值。 
lexicographical_compare 
:比較兩個(gè)序列。重載版本使用了用戶自定義的比較操作。 
lower_bound 
:返回一個(gè) iterator ,它指向在范圍內(nèi)的有序序列中可以插入指定值而不破壞容器順序的第一個(gè)位置。重載函數(shù)使用了自定義的比較操作。 
max 
:返回兩個(gè)元素中的較大的一個(gè),重載版本使用了自定義的比較操作。 
max_element 
:返回一個(gè) iterator ,指出序列中最大的元素。重載版本使用自定義的比較操作。 
min 
:兩個(gè)元素中的較小者。重載版本使用自定義的比較操作。 
min_element 
:類似與 max_element ,不過(guò)返回最小的元素。 
merge 
:合并兩個(gè)有序序列,并存放到另外一個(gè)序列中。重載版本使用自定義的比較。 
mismatch 
:并行的比較兩個(gè)序列,指出第一個(gè)不匹配的位置,它返回一對(duì) iterator ,標(biāo)志第一個(gè)不匹配的元素位置。如果都匹配,返回每個(gè)容器的 last 。重載版本使用自定義的比較操作。 
next_permutation 
:取出當(dāng)前范圍內(nèi)的排列,并將其重新排序?yàn)橄乱粋€(gè)排列。重載版本使用自定義的比較操作。 
nth_element 
:將范圍內(nèi)的序列重新排序,使所有小于第 n 個(gè)元素的元素都出現(xiàn)在它前面,而大于它的都出現(xiàn)在后面,重載版本使用了自定義的比較操作。 
partial_sort 
:對(duì)整個(gè)序列做部分排序,被排序元素的個(gè)數(shù)正好可以被放到范圍內(nèi)。重載版本使用自定義的比較操作。 
partial_sort_copy 
:與 partial_sort 相同,除了將經(jīng)過(guò)排序的序列復(fù)制到另外一個(gè)容器。 
partial_sum 
:創(chuàng)建一個(gè)新的元素序列,其中每個(gè)元素的值代表了范圍內(nèi)該位置之前所有元素之和。重載版本使用了自定義操作替代加法。 
partition 
:對(duì)范圍內(nèi)元素重新排序,使用輸入的函數(shù),把計(jì)算結(jié)果為 true 的元素都放在結(jié)果為 false 的元素之前。 
prev_permutation 
:取出范圍內(nèi)的序列并將它重新排序?yàn)樯弦粋€(gè)序列。如果不存在上一個(gè)序列則返回 false 。重載版本使用自定義的比較操作。 
random_shuffle 
:對(duì)范圍內(nèi)的元素隨機(jī)調(diào)整次序。重載版本輸入一個(gè)隨機(jī)數(shù)產(chǎn)生操作。 
remove 
:刪除在范圍內(nèi)的所有等于指定的元素,注意,該函數(shù)并不真正刪除元素。內(nèi)置數(shù)組不適合使用 remove  remove_if 函數(shù)。 
remove_copy 
:將所有不匹配的元素都復(fù)制到一個(gè)指定容器,返回的 OutputIterator 指向被拷貝的末元素的下一個(gè)位置。 
remove_if 
:刪除所有范圍內(nèi)輸入操作結(jié)果為 true 的元素。 
remove_copy_if 
:將所有不匹配的元素拷貝到一個(gè)指定容器。 
replace 
:將范圍內(nèi)的所有等于 old_value 的元素都用 new_value 替代。 
replace_copy 
:與 replace 類似,不過(guò)將結(jié)果寫(xiě)入另外一個(gè)容器。 
replace_if 
:將范圍內(nèi)的所有操作結(jié)果為 true 的元素用新值替代。 
replace_copy_if 
:類似與 replace_if ,不過(guò)將結(jié)果寫(xiě)入另外一個(gè)容器。 
reverse 
:將范圍內(nèi)元素重新按反序排列。 
reverse_copy 
:類似與 reverse ,不過(guò)將結(jié)果寫(xiě)入另外一個(gè)容器。 
rotate 
:將范圍內(nèi)的元素移到容器末尾,由 middle 指向的元素成為容器第一個(gè)元素。 
rotate_copy 
:類似與 rotate ,不過(guò)將結(jié)果寫(xiě)入另外一個(gè)容器。 
search 
:給出了兩個(gè)范圍,返回一個(gè) iterator ,指向在范圍內(nèi)第一次出現(xiàn)子序列的位置。重載版本使用自定義的比較操作。 
search_n 
:在范圍內(nèi)查找 value 出現(xiàn) n 次的子序列。重載版本使用自定義的比較操作。 
set_difference 
:構(gòu)造一個(gè)排過(guò)序的序列,其中的元素出現(xiàn)在第一個(gè)序列中,但是不包含在第二個(gè)序列中。重載版本使用自定義的比較操作。 
set_intersection 
:構(gòu)造一個(gè)排過(guò)序的序列,其中的元素在兩個(gè)序列中都存在。重載版本使用自定義的比較操作。 
set_symmetric_difference 
:構(gòu)造一個(gè)排過(guò)序的序列,其中的元素在第一個(gè)序列中出現(xiàn),但是不出現(xiàn)在第二個(gè)序列中。重載版本使用自定義的比較操作。 
set_union 
:構(gòu)造一個(gè)排過(guò)序的序列,它包含兩個(gè)序列中的所有的不重復(fù)元素。重載版本使用自定義的比較操作。 
sort 
:以升序重新排列范圍內(nèi)的元素,重載版本使用了自定義的比較操作。 
stable_partition 
:與 partition 類似,不過(guò)它不保證保留容器中的相對(duì)順序。 
stable_sort 
:類似與 sort ,不過(guò)保留相等元素之間的順序關(guān)系。 
swap 
:交換存儲(chǔ)在兩個(gè)對(duì)象中的值。 
swap_range 
:將在范圍內(nèi)的元素與另外一個(gè)序列的元素值進(jìn)行交換。 
transform 
:將輸入的操作作用在范圍內(nèi)的每個(gè)元素上,并產(chǎn)生一個(gè)新的序列。重載版本將操作作用在一對(duì)元素上,另外一個(gè)元素來(lái)自輸入的另外一個(gè)序列。結(jié)果輸出到指定的容器。 
unique 
:清除序列中重復(fù)的元素,和 remove 類似,它也不能真正的刪除元素。重載版本使用了自定義的操作。 
unique_copy 
:類似與 unique ,不過(guò)它把結(jié)果輸出到另外一個(gè)容器。 
upper_bound 
:返回一個(gè) iterator ,它指向在范圍內(nèi)的有序序列中插入 value 而不破壞容器順序的最后一個(gè)位置,該位置標(biāo)志了一個(gè)大于 value 的值。重載版本使用了輸入的比較操作。 
堆算法: C++ 標(biāo)準(zhǔn)庫(kù)提供的是 max-heap 。一共由以下 4 個(gè)泛型堆算法。 
make_heap 
:把范圍內(nèi)的元素生成一個(gè)堆。重載版本使用自定義的比較操作。 
pop_heap 
:并不是真正的把最大元素從堆中彈出,而是重新排序堆。它把 first  last-1 交換,然后重新做成一個(gè)堆。可以使用容器的 back 來(lái)訪問(wèn)被“彈出“的元素或者使用 pop_back 來(lái)真正的刪除。重載版本使用自定義的比較操作。 
push_heap 
:假設(shè) first  last-1 是一個(gè)有效的堆,要被加入堆的元素在位置 last-1 ,重新生成堆。在指向該函數(shù)前,必須先把元素插入容器后。重載版本使用指定的比較。 
sort_heap 
:對(duì)范圍內(nèi)的序列重新排序,它假設(shè)該序列是個(gè)有序的堆。重載版本使用自定義的比較操作。

posted @ 2009-04-10 12:27 Brandon 閱讀(446) | 評(píng)論 (0)編輯 收藏

詳解typedef 的用法

     摘要: typedef 的用法 --摘自一位cnblog的一位大俠 用途一: 定義一種類型的別名,而不只是簡(jiǎn)單的宏替換。可以用作同時(shí)聲明指針型的多個(gè)對(duì)象。比如: char* pa, pb;  // 這多數(shù)不符合我們的意圖,它只聲明了一個(gè)指向字符變量的指針, // 和一個(gè)字符變量; 以下則可行: t...  閱讀全文

posted @ 2009-04-10 09:20 Brandon 閱讀(266) | 評(píng)論 (0)編輯 收藏

CEdit里的光標(biāo)

int   nStart,   nEnd;   

m_edit1.GetSel(nStart,   nEnd);   

if(nStart   ==   nEnd)   
{   
    m_edit1.SetSel(nStart
+1,   nEnd+1);       
}
CEdit不支持SetCaretPos()詳見(jiàn):http://support.microsoft.com/default.aspx?scid=kb;en-us;259949#appliesto

posted @ 2009-04-03 11:14 Brandon 閱讀(1367) | 評(píng)論 (0)編輯 收藏

僅列出標(biāo)題
共2頁(yè): 1 2 
<2025年9月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

導(dǎo)航

統(tǒng)計(jì)

常用鏈接

留言簿(2)

隨筆分類

隨筆檔案

文章分類

文章檔案

收藏夾

IT WEB

常用鏈接

牛人BLOG

學(xué)習(xí)網(wǎng)站

搜索

積分與排名

最新評(píng)論

閱讀排行榜

評(píng)論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            欧美激情第3页| 亚洲视频日本| 久久久久综合| 一本色道久久综合亚洲精品小说| 亚洲欧美国产高清va在线播| 亚洲老司机av| 亚洲欧洲在线一区| 精品88久久久久88久久久| 久久久免费观看视频| 国产精品高潮在线| 正在播放亚洲| 欧美国产在线视频| 欧美a级一区| 久久久噜噜噜久久人人看| 亚洲综合另类| 午夜精品国产更新| 午夜亚洲影视| 亚洲欧美一区在线| 欧美一区二区三区四区在线观看地址 | 国产精品免费在线| 国产精品入口福利| 国产精品自拍视频| 国产网站欧美日韩免费精品在线观看 | 国产精品久久久久久妇女6080 | 久久久久国产精品人| 久久免费99精品久久久久久| 久久亚洲精品一区二区| 狼狼综合久久久久综合网| 免费成人av资源网| 亚洲黄色影院| 亚洲裸体视频| 午夜久久影院| 免费高清在线一区| 欧美日韩精品一二三区| 国产精品jizz在线观看美国 | 欧美一区二区视频在线观看| 一区二区高清在线观看| 亚洲综合另类| 久久裸体艺术| 欧美日韩国产一区二区| 欧美大片免费| 国产精品普通话对白| 国内精品模特av私拍在线观看| 在线播放中文一区| 尤物在线观看一区| 中文日韩在线视频| 国语自产精品视频在线看抢先版结局 | 久久婷婷人人澡人人喊人人爽| 欧美国产高清| 日韩写真在线| 久久久久国产精品麻豆ai换脸| 欧美精品色综合| 国产一区二区三区四区五区美女| 国产美女精品免费电影| 国产精品日韩电影| 亚洲精品在线一区二区| 久久精品国产亚洲aⅴ| 久久精品国产99精品国产亚洲性色 | 亚洲欧美成人在线| 亚洲国产精品久久久久婷婷老年 | 99综合视频| 狂野欧美一区| 91久久精品一区| 久久精品夜色噜噜亚洲a∨ | 亚洲福利一区| 欧美成人免费网| 免费h精品视频在线播放| 亚洲电影免费观看高清| 欧美大片第1页| 欧美成人资源网| 99国产精品久久久久久久成人热| 亚洲国产欧洲综合997久久| 欧美jizz19性欧美| 一区二区三区免费网站| 一区二区三区四区在线| 国产精品综合不卡av| 久久久亚洲成人| 久久夜色精品国产亚洲aⅴ | 日韩视频一区二区在线观看 | 久久久久久自在自线| 亚洲国产一区视频| 亚洲麻豆国产自偷在线| 国产毛片精品视频| 亚洲欧洲一区二区三区久久| 亚洲国产成人高清精品| 亚洲黄色av| 国产精品三区www17con| 浪潮色综合久久天堂| 欧美精品在线一区| 欧美一区激情视频在线观看| 久久久www免费人成黑人精品| 亚洲激情中文1区| 一区二区三区 在线观看视| 国产午夜精品久久| 91久久久在线| 国产一区在线播放| 亚洲精品在线观看免费| 国产日韩在线亚洲字幕中文| 亚洲国产精品久久久久婷婷老年 | 国产精品高潮在线| 美女黄网久久| 国产精品免费视频xxxx| 欧美国产另类| 国产精品一区二区男女羞羞无遮挡 | 久久在线免费| 亚洲在线观看免费视频| 久久久久久久久伊人| 亚洲影院在线| 欧美精品二区| 欧美 日韩 国产 一区| 国产精品hd| 亚洲日韩视频| 亚洲黄色在线视频| 欧美在线影院| 欧美一区二区三区在线看 | 亚洲国产99精品国自产| 亚洲欧美在线x视频| 一区二区三区视频在线看| 久久久亚洲国产美女国产盗摄| 午夜精品视频| 国产精品a级| 99re热精品| 一区二区欧美在线| 欧美国产欧美综合| 亚洲成色777777女色窝| 极品少妇一区二区| 欧美伊久线香蕉线新在线| 午夜视频一区二区| 欧美午夜不卡| 一区二区三区.www| 亚洲小说欧美另类社区| 欧美日韩午夜| 99国产精品久久久久久久| 亚洲精品影视| 欧美剧在线观看| 亚洲精品四区| 亚洲小说区图片区| 国产精品久久午夜| 亚洲欧美电影院| 久久精品国产一区二区三区免费看| 国产精品极品美女粉嫩高清在线| 99精品国产热久久91蜜凸| 性欧美精品高清| 欧美一区视频在线| 欧美精品久久久久久久久久| 亚洲第一区在线观看| 亚洲电影欧美电影有声小说| 久久亚洲国产精品一区二区| 一本不卡影院| 欧美色道久久88综合亚洲精品| 亚洲精品一二区| 亚洲欧美日韩在线不卡| 国产视频精品xxxx| 久久综合狠狠| 亚洲乱码精品一二三四区日韩在线 | 久久成人免费电影| 麻豆精品一区二区综合av| 在线免费精品视频| 欧美精品一区在线观看| 亚洲私拍自拍| 久久福利资源站| 亚洲成人在线| 欧美欧美天天天天操| 亚洲一区二区视频| 老司机午夜精品视频在线观看| 亚洲激情av在线| 欧美四级电影网站| 久久久www成人免费毛片麻豆| 亚洲国产精品毛片| 午夜精品短视频| 亚洲高清色综合| 欧美午夜在线| 麻豆91精品91久久久的内涵| 亚洲理伦在线| 巨乳诱惑日韩免费av| 亚洲精品在线免费| 国产欧美日韩专区发布| 久久夜色精品国产| 亚洲伊人色欲综合网| 亚洲福利av| 久久久久九九九| 在线亚洲激情| 在线日韩电影| 国产精品自拍三区| 欧美伦理91i| 久久久久久久综合| 亚洲免费视频成人| 91久久国产精品91久久性色| 久久激情视频| 亚洲欧美在线x视频| 亚洲精品麻豆| 亚洲第一福利视频| 国产一区自拍视频| 国产精品日本| 欧美日韩精品久久| 欧美激情视频网站| 免费亚洲一区二区| 久久久噜噜噜久久人人看| 亚洲欧美日韩一区二区| 一本色道久久综合亚洲精品不卡 |