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

平凡的天才

目的是為人類造福
posts - 20, comments - 41, trackbacks - 0, articles - 6
  C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

轉自http://blog.csdn.net/fornormandy/archive/2004/08/19/79512.aspx
按照c++標準,編譯器會生成五個默認成員函數(shù):
默認構造函數(shù)
拷貝構造函數(shù)
析構函數(shù)
operator=
operator&


class A
{
public:
A(int i) : m_i(i){}
int m_i;
};

分別說說吧:
1. A a = 0;
首先, compiler認為這樣寫是不符合規(guī)矩的, 因為A = A才是正常行為。
但是她并不放棄, 通過搜索, 發(fā)現(xiàn)A可以根據(jù)一個int構造, 同時這個A(int i)沒有用explicit修飾過。
那么A a = 0; 這樣的一句話隨即轉變成:
A tmp(0);
A a = tmp;
需要說明的是, A a = tmp是調(diào)用的copy ctor, 雖然class A中并沒有, 但是通常不寫copy ctor的話,
compiler都會生成一個memberwise assignment操作性質(zhì)的ctor, 底層實現(xiàn)通常會以memcpy進行。

2. a = 10;
首先, 這樣同ctor的情況一樣, compiler無法直接進行操作。
類推, 等同于代碼:
A tmp(10);
a = tmp;
需要注意的是, a = tmp是調(diào)用的assignment操作, 同ctor一樣,我們自己不寫, 編譯器同樣進行
memberwise assignment操作。

3. fn(A a)
同樣, fn(10)也是不對的, 但是"按照慣例", 呵呵, 會有:
A tmp(10);
fn(tmp);

另外, 為你解惑:
copy ctor的寫法只能是T::T(const T &);
而assignment的寫法可以多變, 即任意. 以T為例,
可以有
T &operator = (int n);
也可有
T &operator = (const char *);
當然, 你要確認如此的定義是對T而言有意義.

然后, 上述a = tmp, 即調(diào)用的默認的、標準的、自動生成的T &operator = (const T &).
開銷是會有一個臨時的A tmp生成, 然后memcpy.
但如果你自已寫了T &operator = (int n), 那么a = 10即意味著a.m_i = 10.
當然, 以開銷而言要視你的T &operator = (int n)是否為inline了.

對于explicit, 當修飾explicit A(int i) : m_i(i){}, 那么即告訴compiler不要在私底下做那么多的轉換動作.
而且自動生成如A tmp(0)這樣的東西是我們不想要的, 因為某些情況下自動轉換這種行為是錯誤的.

最后, 相關此類問題, 還有一個話題, 即class A可以有operator int(), 會在
fn(int n){}
A a(3);
fn(a)
起到魔術般的作用. 關于這個, 留給你自己看看書吧:)

最后,祝學習C++的路上一帆風順。Good luck~

posted @ 2007-03-04 11:32 平凡的天才 閱讀(4817) | 評論 (1)編輯 收藏

原文鏈接:What static_cast<> is actually doing

本文討論static_cast<> 和 reinterpret_cast<>。

介紹
大多程序員在學C++前都學過C,并且習慣于C風格(類型)轉換。當寫C++(程序)時,有時候我們在使用static_cast<>和reinterpret_cast<>時可能會有點模糊。在本文中,我將說明static_cast<>實際上做了什么,并且指出一些將會導致錯誤的情況。

泛型(Generic Types)

        float f = 12.3;
float* pf = &f;

// static cast
// 成功編譯, n = 12
int n = static_cast(f);
// 錯誤,指向的類型是無關的(譯注:即指針變量pf是float類型,現(xiàn)在要被轉換為int類型) //int* pn = static_cast(pf);
//成功編譯
void* pv = static_cast(pf);
//成功編譯, 但是 *pn2是無意義的內(nèi)存(rubbish)
int* pn2 = static_cast(pv);

// reinterpret_cast
//錯誤,編譯器知道你應該調(diào)用static_cast
//int i = reinterpret_cast(f);
//成功編譯, 但是 *pn 實際上是無意義的內(nèi)存,和 *pn2一樣
int* pi = reinterpret_cast(pf);

簡而言之,static_cast<> 將嘗試轉換,舉例來說,如float-到-integer,而reinterpret_cast<>簡單改變編譯器的意圖重新考慮那個對象作為另一類型。

指針類型(Pointer Types)

指針轉換有點復雜,我們將在本文的剩余部分使用下面的類:
class CBaseX
{
public:
int x;
CBaseX() { x = 10; }
void foo() { printf("CBaseX::foo() x=%d\n", x); }
};

class CBaseY
{
public:
int y;
int* py;
CBaseY() { y = 20; py = &y; }
void bar() { printf("CBaseY::bar() y=%d, *py=%d\n", y, *py); }
};

class CDerived : public CBaseX, public CBaseY
{
public:
int z;
};

情況1:兩個無關的類之間的轉換



      // Convert between CBaseX* and CBaseY*
// CBaseX* 和 CBaseY*之間的轉換
CBaseX* pX = new CBaseX();
// Error, types pointed to are unrelated
// 錯誤, 類型指向是無關的
// CBaseY* pY1 = static_cast(pX);
// Compile OK, but pY2 is not CBaseX
// 成功編譯, 但是 pY2 不是CBaseX
CBaseY* pY2 = reinterpret_cast(pX);
// System crash!!
// 系統(tǒng)崩潰!!
// pY2->bar();
正如我們在泛型例子中所認識到的,如果你嘗試轉換一個對象到另一個無關的類static_cast<>將失敗,而reinterpret_cast<>就總是成功“欺騙”編譯器:那個對象就是那個無關類。

情況2:轉換到相關的類
      1. CDerived* pD = new CDerived();
2. printf("CDerived* pD = %x\n", (int)pD);
3.
4. // static_cast CDerived* -> CBaseY* -> CDerived*
//成功編譯,隱式static_cast 轉換
5. CBaseY* pY1 = pD;
6. printf("CBaseY* pY1 = %x\n", (int)pY1);
// 成功編譯, 現(xiàn)在 pD1 = pD
7. CDerived* pD1 = static_cast(pY1);
8. printf("CDerived* pD1 = %x\n", (int)pD1);
9.
10. // reinterpret_cast
// 成功編譯, 但是 pY2 不是 CBaseY*
11. CBaseY* pY2 = reinterpret_cast(pD);
12. printf("CBaseY* pY2 = %x\n", (int)pY2);
13.
14. // 無關的 static_cast
15. CBaseY* pY3 = new CBaseY();
16. printf("CBaseY* pY3 = %x\n", (int)pY3);
// 成功編譯,盡管 pY3 只是一個 "新 CBaseY()"
17. CDerived* pD3 = static_cast(pY3);
18. printf("CDerived* pD3 = %x\n", (int)pD3);
      ---------------------- 輸出 ---------------------------
CDerived* pD = 392fb8
CBaseY* pY1 = 392fbc
CDerived* pD1 = 392fb8
CBaseY* pY2 = 392fb8
CBaseY* pY3 = 390ff0
CDerived* pD3 = 390fec

注意:在將CDerived*用隱式 static_cast<>轉換到CBaseY*(第5行)時,結果是(指向)CDerived*(的指針向后) 偏移了4(個字節(jié))(譯注:4為int類型在內(nèi)存中所占字節(jié)數(shù))。為了知道static_cast<> 實際如何,我們不得不要來看一下CDerived的內(nèi)存布局。

CDerived的內(nèi)存布局(Memory Layout)



如圖所示,CDerived的內(nèi)存布局包括兩個對象,CBaseX 和 CBaseY,編譯器也知道這一點。因此,當你將CDerived* 轉換到 CBaseY*時,它給指針添加4個字節(jié),同時當你將CBaseY*轉換到CDerived*時,它給指針減去4。然而,甚至它即便不是一個CDerived你也可以這樣做。
當然,這個問題只在如果你做了多繼承時發(fā)生。在你將CDerived轉換 到 CBaseX時static_cast<> 和 reinterpret_cast<>是沒有區(qū)別的。

情況3:void*之間的向前和向后轉換

因為任何指針可以被轉換到void*,而void*可以被向后轉換到任何指針(對于static_cast<> 和 reinterpret_cast<>轉換都可以這樣做),如果沒有小心處理的話錯誤可能發(fā)生。

    CDerived* pD = new CDerived();
printf("CDerived* pD = %x\n", (int)pD);

CBaseY* pY = pD; // 成功編譯, pY = pD + 4
printf("CBaseY* pY = %x\n", (int)pY);

void* pV1 = pY; //成功編譯, pV1 = pY
printf("void* pV1 = %x\n", (int)pV1);

// pD2 = pY, 但是我們預期 pD2 = pY - 4
CDerived* pD2 = static_cast(pV1);
printf("CDerived* pD2 = %x\n", (int)pD2);
// 系統(tǒng)崩潰
// pD2->bar();

        ---------------------- 輸出 ---------------------------
CDerived* pD = 392fb8
CBaseY* pY = 392fbc
void* pV1 = 392fbc
CDerived* pD2 = 392fbc

一旦我們已經(jīng)轉換指針為void*,我們就不能輕易將其轉換回原類。在上面的例子中,從一個void* 返回CDerived*的唯一方法是將其轉換為CBaseY*然后再轉換為CDerived*。
但是如果我們不能確定它是CBaseY* 還是 CDerived*,這時我們不得不用dynamic_cast<> 或typeid[2]。

注釋:
1. dynamic_cast<>,從另一方面來說,可以防止一個泛型CBaseY* 被轉換到CDerived*。
2. dynamic_cast<>需要類成為多態(tài),即包括“虛”函數(shù),并因此而不能成為void*。
參考:
1. [MSDN] C++ Language Reference -- Casting
2. Nishant Sivakumar, Casting Basics - Use C++ casts in your VC++.NET programs
3. Juan Soulie, C++ Language Tutorial: Type Casting

posted @ 2006-12-14 23:20 平凡的天才 閱讀(1353) | 評論 (2)編輯 收藏

自己一直以為輸出重載非常簡單,所以從來沒有親手寫過,今天看到一本上上面應該這方面的介紹,就忍不住試了一下,果然問題百出,
在6.0中要重載<<時,不能使用如下的頭文件:
#include<iostream>
using namespace std;
而應該使用程序代碼中所用的形式,具體原因我沒有深入研究,望高人指點

#include<iostream.h>
//using namespace std;

class Rational
{
public:
?Rational(int numerator=0,int denominator=1)
?{
??n=numerator;
??d=denominator;
?}

private:
?int n,d;

friend ostream& operator<<(ostream& s,const Rational& r);
};

ostream& operator<<(ostream& s,const Rational& r)
{
?s<<r.n<<'/'<<r.d;
?return s;
}


int main()
{
?Rational rTemp;
?cout<<rTemp<<endl;

?return 1;
}

posted @ 2006-12-14 22:58 平凡的天才 閱讀(809) | 評論 (1)編輯 收藏

利用MFC的Csocket類實現(xiàn)網(wǎng)絡通信

Mail

  近年來,利用Internet進行網(wǎng)際間通訊,在WWW瀏 覽、FTP、Gopher這些常規(guī)服務,以及在網(wǎng)絡電話、多媒體會議等這些對實時性要求嚴格 的應用中成為研究的熱點,而且已經(jīng)是必需的了。Windows環(huán)境下進行通訊程序設計的最基本方法是應用Windows Sockets實現(xiàn)進程間的通訊,為此微軟提供了大量基于Windows Sockets的通訊API,如WinSockAPI、WinInetAPI和ISAPI,并一直致力于開發(fā)更快、 更容易的通訊API,將其和MFC集成在一起以使通訊編程越來越容易。本實例重點介紹使用MFC的CSocket類編寫網(wǎng)絡通訊程序的方法,并通過使用CSocket類實現(xiàn)了網(wǎng)絡聊天程序。程序編譯運行后的界面效果如圖一所示:

  一、實現(xiàn)方法

  微軟的MFC把復雜的WinSock API函數(shù)封裝到類里,這使得編寫網(wǎng)絡應用程序更容易。CAsyncSocket類逐個封裝了WinSock API,為高級網(wǎng)絡程序員 提供了更加有力而靈活的方法。這個類基于程序員了解網(wǎng)絡通訊的假設,目的是為了在MFC中使用WinSock,程序員有責任處理諸如阻塞、字節(jié)順序和在Unicode與MBCS 間轉換字符的任務。為了給程序員提供更方便的接口以自動處理這些任務,MFC給出 了CSocket類,這個類是由CAsyncSocket類繼承下來的,它提供了比CAsyncSocket更高層的WinSock API接口。Csocket類和CsocketFile類可以與Carchive類一起合作來管理發(fā)送和接收的數(shù)據(jù),這使管理數(shù)據(jù)收發(fā)更加便利。CSocket對象提供阻塞模式,這對于Carchive的同步操作是至關重要的。阻塞函數(shù)(如Receive()、Send()、ReceiveFrom()、SendTo() 和Accept())直到操作完成后才返回控制權,因此如果需要低層控制和高效率,就使用CasyncSock類;如果需要方便,則可使用Csocket類。

  一些網(wǎng)絡應用程序(如網(wǎng)絡電話、多媒體會議工具)對實時性要求非常強,要求能夠直接應用WinSock發(fā)送和接收數(shù)據(jù)。為了充分利用MFC 的優(yōu)勢,首選方案應當是MFC中的CAsyncSocket類或CSocket類,這兩個類完全封裝了WinSock API,并提供更多的便利。本實例介紹應用這兩個類的編程模型,并引出相關的成員函數(shù)與一些概念的解釋。

  CSocket類是由CAsyncSocket繼承而來的,事實上,在MFC中CAsyncSocket 逐個封裝了WinSock API,每個CAsyncSocket對象代表一個Windows Socket對象,使用CAsyncSocket 類要求程序員對網(wǎng)絡編程較為熟悉。相比起來,CSocket類是CAsyncSocket的派生類, 繼承了它封裝的WinSock API。

  一個CSocket對象代表了一個比CAsyncSocket對象更高層次的Windows Socket的抽象,CSocket類與CSocketFile類和CArchive類一起工作來發(fā)送和接收數(shù)據(jù),因此使用它更加容易使用。CSocket對象提供阻塞模式,因為阻塞功 能對于CArchive的同步操作是至關重要的。在這里有必要對阻塞的概念作一解釋: 一個socket可以處于"阻塞模式"或"非阻塞模式",當一個套接字處于阻塞模式(即同步操作)時,它的阻塞函數(shù)直到操作完成才會返回控制權,之所以稱為阻塞是因為此套接字的阻塞函數(shù)在完成操作返回之前什么也不能做。如果一個socket處于非阻塞模式(即異步操作),則會被調(diào)用函數(shù)立即返回。在CAsyncSocket類中可以用GetLastError 成員函數(shù)查詢最后的錯誤,如果錯誤是WSAEWOULDBLOCK則說明有阻塞,而CSocket絕不會返回WSAEWOULDBLOCK,因為它自己管理阻塞。微軟建議盡量使用非阻塞模式,通過網(wǎng)絡事件的發(fā)生而通知應用程序進行相應的處理。但在CSocket類中,為了利用CArchive 處理通訊中的許多問題和簡化編程,它的一些成員函數(shù)總是具有阻塞性質(zhì)的,這是因為CArchive類需要同步的操作。

  在Win32環(huán)境下,如果要使用具有阻塞性質(zhì)的套接字,應該放在獨立的工作線程中處理,利用多線程的方法使阻塞不至于干擾其他線程,也不會把CPU時間浪費在阻塞上。多線程的方法既可以使程序員享受CSocket帶 來的簡化編程的便利,也不會影響用戶界面對用戶的反應。

  CAsyncSocket類編程模型

  在一個MFC應用程序中,要想輕松處理多個網(wǎng) 絡協(xié)議,而又不犧牲靈活性時,可以考慮使用CAsyncSocket類,它的效率比CSocket 類要高。CAsyncSocket類針對字節(jié)流型套接字的編程模型簡述如下:

  1、構造一個CAsyncSocket對象,并用這個 對象的Create成員函數(shù)產(chǎn)生一個Socket句柄。可以按如下兩種方法構造:


CAsyncSocket sock; //使用默認參數(shù)產(chǎn)生一個字節(jié)流套接字
Sock.Create();

  或在指定端口號產(chǎn)生一個數(shù)據(jù)報套接字


CAsyncSocket*pSocket=newCAsyncSocket;
intnPort=27;
pSocket->Create(nPort,SOCK-DGRAM);

  第一種方法在棧上產(chǎn)生一個CAsyncSocket對象, 而第二種方法在堆上產(chǎn)生CAsyncSocket對象;第一種方法中Create()成員函數(shù)用缺省參數(shù)產(chǎn)生一個字節(jié)流套接字,第二種方法中用Create()成員函數(shù)在指定的端口產(chǎn)生一個數(shù)字報套接字。Create()函數(shù)的原型為:


BOOL Create( UINT nSocketPort = 0, int nSocketType = SOCK_STREAM,
LPCTSTR lpszSocketAddress = NULL );

  該函數(shù)的參數(shù)有:

  1)端口,UINT類型。注意:如果是服務方,則使 用一個眾所周知的端口供服務方連接;如果是客戶方,典型做法是接受默認參數(shù),使 套接字可以自主選擇一個可用端口;

  2)socket 類型,可以是SOCK-STREAM(默認值,字節(jié)流)或SOCK-DGRAM(數(shù)據(jù)報);

  3)socket的地址,例如"ftp.gliet.edu.cn"或"202.193.64.33"。

  2、如是客戶方程序,用CAsyncSocket∷Connect()成員函數(shù)連接到服務方;如是服務方程序,用CAsyncSocket∷Listen()成員函數(shù)開始 監(jiān)聽,一旦收到連接請求,則調(diào)用CAsyncSocket∷Accept()成員函數(shù)開始接收。注意:CAsyncSocket ∷Accept()成員函數(shù)要用一個新的并且是空的CAsyncSocket對象作為它的參數(shù),這里所說 的"空的"指的是這個新對象還沒有調(diào)用Create()成員函數(shù)。

  3、調(diào)用其他的CAsyncSocket類的Receive()、ReceiveFrom()、Send()和SendTo()等成員函數(shù)進行數(shù)據(jù)通信。

  4、通訊結束后,銷毀CAsyncSocket對象。如果是在棧上產(chǎn)生的CAsyncSocket對象,則對象超出定義的范圍時自動被析構;如果是在堆上產(chǎn)生,也就是用了new這個操作符,則必須使用delete操作符銷毀CAsyncSocket 對象。

  CSocket類編程模型

  使用CSocket對象涉及CArchive和CSocketFile 類對象。以下介紹的針對字節(jié)流型套接字的操作步驟中,只有第3步對于客戶方和服務方操作是不同的,其他步驟都相同。

  1、構造一個CSocket對象。

  2、使用這個對象的Create()成員函數(shù)產(chǎn)生一個socket對象。在客戶方程序中,除非需要數(shù)據(jù)報套接字,Create()函數(shù)一般情況下應該使用默認參數(shù)。而對于服務方程序,必須在調(diào)用Create時指定一個端口。需要注意的是,Carchive類對象不能與數(shù)據(jù)報(UDP)套接字一起工作,因此對于數(shù)據(jù)報套接字,CAsyncSocket和CSocket 的使用方法是一樣的。

  3、如果是客戶方套接字,則調(diào)用CAsyncSocket ∷Connect()函數(shù)與服務方套接字連接;如果是服務方套接字,則調(diào)用CAsyncSocket∷Listen()開始監(jiān)聽來自客戶方的連接請求,收到連接請求后,調(diào)用CAsyncSocket∷Accept()函數(shù)接受請求,建立連接。請注意Accept()成員函數(shù)需要一個新的并且為空的CSocket對象作為它的參數(shù),解釋同上。

  4、產(chǎn)生一個CSocketFile對象,并把它與CSocket 對象關聯(lián)起來。

  5、為接收和發(fā)送數(shù)據(jù)各產(chǎn)生一個CArchive 對象,把它們與CSocketFile對象關聯(lián)起來。切記CArchive是不能和數(shù)據(jù)報套接字一起工作的。

  6、使用CArchive對象的Read()、Write()等函數(shù)在客戶與服務方傳送數(shù)據(jù)。

  7、通訊完畢后,銷毀CArchive、CSocketFile和CSocket對象。

  二、編程步驟

  1、 啟動Visual C++6.0,生成一個基于對話框架的應用程序,將該程序命名為"Test";

  2、 按照圖一所示的效果圖設置對話框的界面;

  3、 使用Class Wizard為應用程序的按鈕添加鼠標單擊消息響應函數(shù);

  4、 使用Class Wizard在應用程序中定義新類CNewSocket,其基類選擇為CSocket;

  5、 添加代碼,編譯運行程序。

三、程序代碼

////////////////////////////////////////////////// NewSocket.h : header file
#if !defined(AFX_NEWSOCKET_H__8CE2ED73_1D56_11D3_9928_00A0C98F3E85__INCLUDED_)
#define AFX_NEWSOCKET_H__8CE2ED73_1D56_11D3_9928_00A0C98F3E85__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
class CTestDlg;
#include <afxsock.h>

class CNewSocket : public CSocket
{
// Attributes
public:

// Operations
public:
CNewSocket();
virtual ~CNewSocket();

// Overrides
public:
int m_Status;
void GetDlg(CTestDlg *dlg);
CTestDlg *m_dlg;
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CNewSocket)
public:
virtual void OnAccept(int nErrorCode);
virtual void OnReceive(int nErrorCode);
virtual void OnClose(int nErrorCode);
//}}AFX_VIRTUAL
// Generated message map functions
//{{AFX_MSG(CNewSocket)
// NOTE - the ClassWizard will add and remove member functions here.
//}}AFX_MSG
// Implementation
protected:
};
#endif

//////////////////////////////////////////////////////// NewSocket.cpp : implementation file
#include "stdafx.h"
#include "Test.h"
#include "NewSocket.h"
#include "TestDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

CNewSocket::CNewSocket()
{}

CNewSocket::~CNewSocket()
{}

#if 0
BEGIN_MESSAGE_MAP(CNewSocket, CSocket)
//{{AFX_MSG_MAP(CNewSocket)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
#endif // 0

void CNewSocket::OnAccept(int nErrorCode)
{
 if (m_dlg->m_ClientSocket==NULL) m_dlg->OnAccept();
 CSocket::OnAccept(nErrorCode);
}

void CNewSocket::OnReceive(int nErrorCode)
{
 m_dlg->OnReceive();
 CSocket::OnReceive(nErrorCode);
}

void CNewSocket::GetDlg(CTestDlg *dlg)
{
 m_dlg=dlg;
}

void CNewSocket::OnClose(int nErrorCode)
{
 m_dlg->OnClose();
 CSocket::OnClose(nErrorCode);
}

///////////////////////////////////////////////////////////////// TestDlg.h : header file
#if !defined(AFX_TESTDLG_H__EDDDE196_1BF1_11D3_BE77_0000B454AEE4__INCLUDED_)
#define AFX_TESTDLG_H__EDDDE196_1BF1_11D3_BE77_0000B454AEE4__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
#include "NewSocket.h"

class CTestDlg : public CDialog
{
 // Construction
 public:
  void SocketReset();
  void OnClose();
  void OnReceive();
  void OnAccept();
  CSocketFile *m_file;
  CArchive *m_arOut;
  CArchive *m_arIn;
  CNewSocket* m_ServerSocket;
  CNewSocket* m_ClientSocket;
  CTestDlg(CWnd* pParent = NULL); // standard constructor
  // Dialog Data
  //{{AFX_DATA(CTestDlg)
  enum { IDD = IDD_TEST_DIALOG };
  CString m_Info;
  CString m_Output;
  CString m_Input;
  CString m_Connect;
  CString m_IPAddress;
  UINT m_Port;
  int m_Status;
  //}}AFX_DATA
  // ClassWizard generated virtual function overrides
  //{{AFX_VIRTUAL(CTestDlg)
 protected:
  virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
  //}}AFX_VIRTUAL
  // Implementation
 protected:
  HICON m_hIcon;
  // Generated message map functions
  //{{AFX_MSG(CTestDlg)
  virtual BOOL OnInitDialog();
  afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
  afx_msg void OnPaint();
  afx_msg HCURSOR OnQueryDragIcon();
  afx_msg void OnConnect();
  afx_msg void OnDisconnect();
  afx_msg void OnSend();
  afx_msg void OnServerradio();
  afx_msg void OnClientradio();
  afx_msg void OnSendclear();
  afx_msg void OnReceiveclear();
  //}}AFX_MSG
  DECLARE_MESSAGE_MAP()
 };
#endif

//////////////////////////////////////////////////////////////// TestDlg.cpp : implementation file
#include "stdafx.h"
#include "Test.h"
#include "TestDlg.h"
#include <afxsock.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

class CAboutDlg : public CDialog
{
 public:
  CAboutDlg();
  // Dialog Data
  //{{AFX_DATA(CAboutDlg)
   enum { IDD = IDD_ABOUTBOX };
  //}}AFX_DATA
  // ClassWizard generated virtual function overrides
  //{{AFX_VIRTUAL(CAboutDlg)
 protected:
  virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
  //}}AFX_VIRTUAL
  // Implementation
 protected:
  //{{AFX_MSG(CAboutDlg)
  //}}AFX_MSG
 DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
 //{{AFX_DATA_INIT(CAboutDlg)
 //}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
 CDialog::DoDataExchange(pDX);
 //{{AFX_DATA_MAP(CAboutDlg)
 //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
 //{{AFX_MSG_MAP(CAboutDlg)
 // No message handlers
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()

CTestDlg::CTestDlg(CWnd* pParent /*=NULL*/)
: CDialog(CTestDlg::IDD, pParent)
{
 //{{AFX_DATA_INIT(CTestDlg)
  m_Info = _T("");
  m_Output = _T("");
  m_Input = _T("");
  m_Connect = _T("");
  m_IPAddress = _T("");
  m_Port = 0;
  m_Status = -1;
 //}}AFX_DATA_INIT
 // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CTestDlg::DoDataExchange(CDataExchange* pDX)
{
 CDialog::DoDataExchange(pDX);
 //{{AFX_DATA_MAP(CTestDlg)
  DDX_Text(pDX, IDC_OUTPUTEDIT, m_Output);
  DDX_Text(pDX, IDC_INPUTEDIT, m_Input);
  DDX_Text(pDX, IDC_CONNECTEDIT, m_Connect);
  DDX_Text(pDX, IDC_IPADDRESS, m_IPAddress);
  DDV_MaxChars(pDX, m_IPAddress, 15);
  DDX_Text(pDX, IDC_PORT, m_Port);
  DDX_Radio(pDX, IDC_SERVERRADIO, m_Status);
 //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CTestDlg, CDialog)
//{{AFX_MSG_MAP(CTestDlg)
 ON_WM_SYSCOMMAND()
 ON_WM_PAINT()
 ON_WM_QUERYDRAGICON()
 ON_BN_CLICKED(IDC_CONNECTBUTTON, OnConnect)
 ON_BN_CLICKED(IDC_DISCONNECTBUTTON, OnDisconnect)
 ON_BN_CLICKED(IDC_SENDBUTTON, OnSend)
 ON_BN_CLICKED(IDC_SERVERRADIO, OnServerradio)
 ON_BN_CLICKED(IDC_CLIENTRADIO, OnClientradio)
 ON_BN_CLICKED(IDC_SENDCLEARBUTTON, OnSendclear)
 ON_BN_CLICKED(IDC_RECEIVECLEARBUTTON, OnReceiveclear)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

BOOL CTestDlg::OnInitDialog()
{
 CDialog::OnInitDialog();
 // Add "About..." menu item to system menu.
 // IDM_ABOUTBOX must be in the system command range.
 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
 ASSERT(IDM_ABOUTBOX < 0xF000);
 CMenu* pSysMenu = GetSystemMenu(FALSE);
 if (pSysMenu != NULL)
 {
  CString strAboutMenu;
  strAboutMenu.LoadString(IDS_ABOUTBOX);
  if (!strAboutMenu.IsEmpty())
  {
   pSysMenu->AppendMenu(MF_SEPARATOR);
   pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
  }
 }
 // Set the icon for this dialog. The framework does this automatically
 // when the application's main window is not a dialog
 SetIcon(m_hIcon, TRUE); // Set big icon
 SetIcon(m_hIcon, FALSE); // Set small icon
 m_Status=-1;
 m_ServerSocket=NULL;
 m_ClientSocket=NULL;
 m_arIn=NULL;
 m_arOut=NULL;
 m_file=NULL;
 m_Connect="";
 m_IPAddress="202.207.243.29";
 m_Port=5000;
 GetDlgItem(IDC_IPADDRESS)->EnableWindow(FALSE);
 GetDlgItem(IDC_PORT)->EnableWindow(FALSE);
 UpdateData(FALSE);
 return TRUE; // return TRUE unless you set the focus to a control
}

void CTestDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
 if ((nID & 0xFFF0) == IDM_ABOUTBOX)
 {
  CAboutDlg dlgAbout;
  dlgAbout.DoModal();
 }
 else
 {
  CDialog::OnSysCommand(nID, lParam);
 }
}

// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CTestDlg::OnPaint()
{
 if (IsIconic())
 {
  CPaintDC dc(this); // device context for painting
  SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
  // Center icon in client rectangle
  int cxIcon = GetSystemMetrics(SM_CXICON);
  int cyIcon = GetSystemMetrics(SM_CYICON);
  CRect rect;
  GetClientRect(&rect);
  int x = (rect.Width() - cxIcon + 1) / 2;
  int y = (rect.Height() - cyIcon + 1) / 2;
  // Draw the icon
  dc.DrawIcon(x, y, m_hIcon);
 }
 else
 {
  CDialog::OnPaint();
 }
}

// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CTestDlg::OnQueryDragIcon()
{
 return (HCURSOR) m_hIcon;
}

void CTestDlg::OnConnect()
{
 CString msg;
 UpdateData(TRUE);
 if (m_Status==0 ) //server
 {
  if ( m_ServerSocket!=NULL)
  {
   m_Connect="Please disconnect!";
   UpdateData(FALSE);
  }
  else
  {
   m_Connect="Waiting for Client...";
   UpdateData(FALSE);
   if(!AfxSocketInit())
   {
    MessageBox("WindowsSocket initial failed!","Send",MB_ICONSTOP);
    return;
   }
   m_ServerSocket=new CNewSocket;
   m_ServerSocket->m_Status=m_Status;
   m_ServerSocket->GetDlg(this);
   if(!m_ServerSocket->Create(m_Port))
     MessageBox("SendSocket create failed!", "Send",MB_ICONSTOP);
   else
   {
    m_ServerSocket->Listen();
   }
  }
 }
 else
 {
  if (m_Status==1)
  {
   if (m_ClientSocket!=NULL)
   {
    m_Connect="Please disconnect!";
    UpdateData(FALSE);
   }
   else
   {
    m_Connect="Connect to the Server...";
    UpdateData(FALSE);
    if(!AfxSocketInit())
    {
     MessageBox("WindowsSocket initial failed!","Receive",MB_ICONSTOP);
     return;
    }  
    m_ClientSocket=new CNewSocket;
    m_ClientSocket->GetDlg(this);
    m_ClientSocket->m_Status=m_Status;
    if(!m_ClientSocket->Create())
    {
     MessageBox("ReceiveSocket create failed!","Receive",MB_ICONSTOP);
     return;
    }
    else
    {
     if (!m_ClientSocket->Connect(m_IPAddress,m_Port))
     {
      CString str=m_Connect;
      SocketReset();
      m_Connect=str;
      m_Connect+="Error!";
      UpdateData(FALSE);
     }
     else
     {
      m_Connect+="OK!";
      m_file=new CSocketFile(m_ClientSocket);
      m_arIn=new CArchive(m_file, CArchive::load);
      m_arOut=new CArchive(m_file, CArchive::store);
     }
     UpdateData(FALSE);
    }
   }
  }
 }
 if (m_Status==-1)
 {
  msg="Please choose the status!";
  AfxMessageBox(msg);
 }
}

void CTestDlg::OnSend()
{
 if (m_arOut)
 {
  if (m_Status==0)
  {
   UpdateData(TRUE);
   *m_arOut<<m_Output;
   m_arOut->Flush();
  }
  else
  {
   UpdateData(TRUE);
   *m_arOut<<m_Output;
   m_arOut->Flush();
  }
 }
 else AfxMessageBox("Not connected!");
}

void CTestDlg::OnAccept()
{
 m_Connect+="OK!";
 UpdateData(FALSE);
 m_ClientSocket=new CNewSocket;
 m_ClientSocket->GetDlg(this);
 m_ServerSocket->Accept(*m_ClientSocket);
 m_ClientSocket->m_Status=m_ServerSocket->m_Status;
 m_file=new CSocketFile(m_ClientSocket);
 m_arIn=new CArchive(m_file, CArchive::load);
 m_arOut=new CArchive(m_file, CArchive::store);
}

void CTestDlg::OnReceive()
{
 *m_arIn>>m_Input;
 UpdateData(FALSE);
}

void CTestDlg::OnDisconnect()
{
 if (m_arOut!=NULL)
 {
  SocketReset();
  m_Connect="Disconnected!";
  UpdateData(FALSE);
 }
}

void CTestDlg::OnClose()
{
 if (m_ClientSocket->m_Status==0) m_Connect="Client ";
 else m_Connect="Server ";
 m_Connect+="has disconnected!";
 UpdateData(FALSE);
}

void CTestDlg::SocketReset()
{
 if (m_arIn!=NULL)
 {
  delete m_arIn;
  m_arIn=NULL;
 }
 if (m_arOut!=NULL)
 {
  delete m_arOut;
  m_arOut=NULL;
 }
 if (m_file!=NULL)
 {
  delete m_file;
  m_file=NULL;
 }
 if (m_ClientSocket!=NULL)
 {
  delete m_ClientSocket;
  m_ClientSocket=NULL;
 }
 if (m_ServerSocket!=NULL)
 {
  delete m_ServerSocket;
  m_ServerSocket=NULL;
 }
 m_Connect="";
 UpdateData(FALSE);
}

void CTestDlg::OnServerradio()
{
 UpdateData(TRUE);
 GetDlgItem(IDC_IPADDRESS)->EnableWindow(FALSE);
 GetDlgItem(IDC_PORT)->EnableWindow(TRUE);
 UpdateData(FALSE);
}

void CTestDlg::OnClientradio()
{
 UpdateData(TRUE);
 GetDlgItem(IDC_IPADDRESS)->EnableWindow(TRUE);
 GetDlgItem(IDC_PORT)->EnableWindow(TRUE);
 UpdateData(FALSE);
}

void CTestDlg::OnSendclear()
{
 m_Output="";
 UpdateData(FALSE);
}

void CTestDlg::OnReceiveclear()
{
 m_Input="";
 UpdateData(FALSE);
}

  四、小結

  本實例介紹了CAsyncSocket、CSocket類,并通過使用CSocket類實現(xiàn)了網(wǎng)絡聊天程序。讀者朋友還可以通過MFC CArchive 對象進行信息的接發(fā)操作,使得網(wǎng)絡傳輸如同使用MFC的文檔連載協(xié)議(Serialization protocol),簡捷易用。

posted @ 2006-12-10 14:51 平凡的天才 閱讀(2038) | 評論 (0)編輯 收藏

在C語言編程中,static的一個作用是信息屏蔽!

比方說,你自己定義了一個文件?--?該文件中有一系列的函數(shù)以及變量的聲明和定義!

你希望該文件中的一些函數(shù)和變量只能被該文件中的函數(shù)使用,那么,你可以在該函數(shù)、變量的前面加上static,代表他們只能被當前文件中的函數(shù)使用!


而在C++中,用static來作為信息屏蔽就顯得沒有必要了!因為,C++有了信息屏蔽的利器?--?class機制!

類中的private屬性的變量和函數(shù)就對外禁止訪問!


然后是C/C++通用的函數(shù)作用域的static型的變量!其目的,也是為了信息的屏蔽!


int?fun()?{
???static?int?a?=?1;
???a++;
}

在第一次進入這個函數(shù)的時候,變量a被初始化為1!并接著自增1!

以后每次進入該函數(shù),a就不會被再次初始化了,僅進行自增1的操作!

在static發(fā)明前,要達到同樣的功能,則只能使用全局變量:

int?a?=?1;

int?fun()?{
???a++;
}

那么,a的值就有可能被其他函數(shù)所改變!



最后,說說類中的static變量和函數(shù)。


這種存儲屬性的變量和函數(shù)是同一種類的不同實例之間通信的橋梁!


#include?<iostream>
using?namespace?std;

class?A?{
public:
????static?int?num;????//????統(tǒng)計創(chuàng)建了多少個實例
????A?()?{num++};????//????每創(chuàng)建一個實例,就讓num自增1

????//????返回通過構造函數(shù)所創(chuàng)建過的A類實例的數(shù)目
????static?int?how_many_instance()?{
????????return?num;
????}
}

static?A::num?=?0;????//????需要在類申明的外部單獨初始化!


int?main()?{
????cout?<<?A::how_many_instance()?<<?endl;
????A?a,?b,?c,?d;
????cout?<<?A::how_many_instance()?<<?endl;
????system("pause");
}


一般,在類內(nèi)部,是通過static屬性的函數(shù),訪問static屬性的變量!

補充一點,在類中,static型的成員函數(shù),由于是類所擁有的,而不是具體對象所有的,這一點對于windows的回調(diào)機制非常有用。
因為對于回調(diào)函數(shù)而言,windows不會借助任何對象去調(diào)用它,也就不會傳遞this指針,那么對于一般成員函數(shù)作為回調(diào)函數(shù)的后果,就是堆棧中有一個隨機的變量會成為this指針,這當然會引發(fā)程序的崩潰。
而static函數(shù),由于是整個類的,屏蔽了this指針。因此,如果成員函數(shù)作為回調(diào)函數(shù),就應該用static去修飾它。

posted @ 2006-12-09 16:02 平凡的天才 閱讀(11707) | 評論 (4)編輯 收藏

關于Debug和Release之本質(zhì)區(qū)別??????????????????????????????????????

經(jīng)常在 CSDN 上看見有人問 Debug 運行正常但 Release 失敗的問題。以往的討論往往是
經(jīng)驗性的,并沒有指出會這樣的真正原因是什么,要想找出真正的原因通常要憑運氣。最
近我看了一些這方面的書,又參考了 CSDN 上的一些帖子,然后深入研究了一下關于二者
的不同。以下是我的一些體會,拿來與大家共享。
--------------------------------------
本文主要包含如下內(nèi)容:
1. Debug 和 Release 編譯方式的本質(zhì)區(qū)別
2. 哪些情況下 Release 版會出錯
2. 怎樣“調(diào)試” Release 版的程序
--------------------------------------

??????????? 關于Debug和Release之本質(zhì)區(qū)別的討論

一、Debug 和 Release 編譯方式的本質(zhì)區(qū)別

??? Debug 通常稱為調(diào)試版本,它包含調(diào)試信息,并且不作任何優(yōu)化,便于程序員調(diào)試程
序。Release 稱為發(fā)布版本,它往往是進行了各種優(yōu)化,使得程序在代碼大小和運行速度
上都是最優(yōu)的,以便用戶很好地使用。
??? Debug 和 Release 的真正秘密,在于一組編譯選項。下面列出了分別針對二者的選項
(當然除此之外還有其他一些,如/Fd /Fo,但區(qū)別并不重要,通常他們也不會引起 Rele
ase 版錯誤,在此不討論)

Debug 版本:
?/MDd /MLd 或 /MTd?? 使用 Debug runtime library(調(diào)試版本的運行時刻函數(shù)庫)
?/Od???????????????? 關閉優(yōu)化開關
?/D "_DEBUG"???????? 相當于 #define _DEBUG,打開編譯調(diào)試代碼開關(主要針對
???????????????????? assert函數(shù))
?/ZI???????????????? 創(chuàng)建 Edit and continue(編輯繼續(xù))數(shù)據(jù)庫,這樣在調(diào)試過
???????????????????? 程中如果修改了源代碼不需重新編譯
?/GZ???????????????? 可以幫助捕獲內(nèi)存錯誤
?/Gm???????????????? 打開最小化重鏈接開關,減少鏈接時間

Release 版本:
?/MD /ML 或 /MT????? 使用發(fā)布版本的運行時刻函數(shù)庫
?/O1 或 /O2????????? 優(yōu)化開關,使程序最小或最快
?/D "NDEBUG"???????? 關閉條件編譯調(diào)試代碼開關(即不編譯assert函數(shù))
?/GF???????????????? 合并重復的字符串,并將字符串常量放到只讀內(nèi)存,防止
???????????????????? 被修改

??? 實際上,Debug 和 Release 并沒有本質(zhì)的界限,他們只是一組編譯選項的集合,編譯
器只是按照預定的選項行動。事實上,我們甚至可以修改這些選項,從而得到優(yōu)化過的調(diào)
試版本或是帶跟蹤語句的發(fā)布版本。

二、哪些情況下 Release 版會出錯

??? 有了上面的介紹,我們再來逐個對照這些選項看看 Release 版錯誤是怎樣產(chǎn)生的

?1. Runtime Library:鏈接哪種運行時刻函數(shù)庫通常只對程序的性能產(chǎn)生影響。調(diào)試版本
的 Runtime Library 包含了調(diào)試信息,并采用了一些保護機制以幫助發(fā)現(xiàn)錯誤,因此性能
不如發(fā)布版本。編譯器提供的 Runtime Library 通常很穩(wěn)定,不會造成 Release 版錯誤
;倒是由于 Debug 的 Runtime Library 加強了對錯誤的檢測,如堆內(nèi)存分配,有時會出
現(xiàn) Debug 有錯但 Release 正常的現(xiàn)象。應當指出的是,如果Debug有錯,即使 Release
正常,程序肯定是有 Bug 的,只不過可能是 Release版的某次運行沒有表現(xiàn)出來而已。


?2. 優(yōu)化:這是造成錯誤的主要原因,因為關閉優(yōu)化時源程序基本上是直接翻譯的,而打
開優(yōu)化后編譯器會作出一系列假設。這類錯誤主要有以下幾種:

??? (1) 幀指針(Frame Pointer)省略(簡稱 FPO ):在函數(shù)調(diào)用過程中,所有調(diào)用信息
(返回地址、參數(shù))以及自動變量都是放在棧中的。若函數(shù)的聲明與實現(xiàn)不同(參數(shù)、返
回值、調(diào)用方式),就會產(chǎn)生錯誤————但 Debug 方式下,棧的訪問通過 EBP 寄存器
保存的地址實現(xiàn),如果沒有發(fā)生數(shù)組越界之類的錯誤(或是越界“不多”),函數(shù)通常能
正常執(zhí)行;Release 方式下,優(yōu)化會省略 EBP 棧基址指針,這樣通過一個全局指針訪問棧
就會造成返回地址錯誤是程序崩潰。C++ 的強類型特性能檢查出大多數(shù)這樣的錯誤,但如
果用了強制類型轉換,就不行了。你可以在 Release 版本中強制加入 /Oy- 編譯選項來關
掉幀指針省略,以確定是否此類錯誤。此類錯誤通常有:

???? ● MFC 消息響應函數(shù)書寫錯誤。正確的應為
????? afx_msg LRESULT OnMessageOwn(WPARAM wparam, LPARAM lparam);
????? ON_MESSAGE 宏包含強制類型轉換。防止這種錯誤的方法之一是重定義 ON_MESSAGE
?宏,把下列代碼加到 stdafx.h 中(在#include "afxwin.h"之后),函數(shù)原形錯誤時編譯
會報錯
????? #undef ON_MESSAGE
????? #define ON_MESSAGE(message, memberFxn) \
????? { message, 0, 0, 0, AfxSig_lwl, \
????? (AFX_PMSG)(AFX_PMSGW)(static_cast< LRESULT (AFX_MSG_CALL \
????? CWnd::*)(WPARAM, LPARAM) > (&memberFxn) },

??? (2) volatile 型變量:volatile 告訴編譯器該變量可能被程序之外的未知方式修改
(如系統(tǒng)、其他進程和線程)。優(yōu)化程序為了使程序性能提高,常把一些變量放在寄存器
中(類似于 register 關鍵字),而其他進程只能對該變量所在的內(nèi)存進行修改,而寄存
器中的值沒變。如果你的程序是多線程的,或者你發(fā)現(xiàn)某個變量的值與預期的不符而你確
信已正確的設置了,則很可能遇到這樣的問題。這種錯誤有時會表現(xiàn)為程序在最快優(yōu)化出
錯而最小優(yōu)化正常。把你認為可疑的變量加上 volatile 試試。

??? (3) 變量優(yōu)化:優(yōu)化程序會根據(jù)變量的使用情況優(yōu)化變量。例如,函數(shù)中有一個未被
使用的變量,在 Debug 版中它有可能掩蓋一個數(shù)組越界,而在 Release 版中,這個變量
很可能被優(yōu)化調(diào),此時數(shù)組越界會破壞棧中有用的數(shù)據(jù)。當然,實際的情況會比這復雜得
多。與此有關的錯誤有:
???? ● 非法訪問,包括數(shù)組越界、指針錯誤等。例如
???????? void fn(void)
???????? {
?????????? int i;
?????????? i = 1;
?????????? int a[4];
?????????? {
???????????? int j;
???????????? j = 1;
?????????? }
?????????? a[-1] = 1;//當然錯誤不會這么明顯,例如下標是變量
?????????? a[4] = 1;
???????? }
?????? j 雖然在數(shù)組越界時已出了作用域,但其空間并未收回,因而 i 和 j 就會掩蓋越
界。而 Release 版由于 i、j 并未其很大作用可能會被優(yōu)化掉,從而使棧被破壞。

3. _DEBUG 與 NDEBUG :當定義了 _DEBUG 時,assert() 函數(shù)會被編譯,而 NDEBUG 時不
被編譯。除此之外,VC++中還有一系列斷言宏。這包括:

??? ANSI C 斷言???????? void assert(int expression );
??? C Runtime Lib 斷言? _ASSERT( booleanExpression );
??????????????????????? _ASSERTE( booleanExpression );
??? MFC 斷言??????????? ASSERT( booleanExpression );
??????????????????????? VERIFY( booleanExpression );
??????????????????????? ASSERT_VALID( pObject );
??????????????????????? ASSERT_KINDOF( classname, pobject );
??? ATL 斷言??????????? ATLASSERT( booleanExpression );
??? 此外,TRACE() 宏的編譯也受 _DEBUG 控制。

??? 所有這些斷言都只在 Debug版中才被編譯,而在 Release 版中被忽略。唯一的例外是
?VERIFY() 。事實上,這些宏都是調(diào)用了 assert() 函數(shù),只不過附加了一些與庫有關的
調(diào)試代碼。如果你在這些宏中加入了任何程序代碼,而不只是布爾表達式(例如賦值、能
改變變量值的函數(shù)調(diào)用 等),那么 Release 版都不會執(zhí)行這些操作,從而造成錯誤。初
學者很容易犯這類錯誤,查找的方法也很簡單,因為這些宏都已在上面列出,只要利用 V
C++ 的 Find in Files 功能在工程所有文件中找到用這些宏的地方再一一檢查即可。另外
,有些高手可能還會加入 #ifdef _DEBUG 之類的條件編譯,也要注意一下。
??? 順便值得一提的是 VERIFY() 宏,這個宏允許你將程序代碼放在布爾表達式里。這個
宏通常用來檢查 Windows API 的返回值。有些人可能為這個原因而濫用 VERIFY() ,事實
上這是危險的,因為 VERIFY() 違反了斷言的思想,不能使程序代碼和調(diào)試代碼完全分離
,最終可能會帶來很多麻煩。因此,專家們建議盡量少用這個宏。

4. /GZ 選項:這個選項會做以下這些事

??? (1) 初始化內(nèi)存和變量。包括用 0xCC 初始化所有自動變量,0xCD ( Cleared Data
) 初始化堆中分配的內(nèi)存(即動態(tài)分配的內(nèi)存,例如 new ),0xDD ( Dead Data ) 填充
已被釋放的堆內(nèi)存(例如 delete ),0xFD( deFencde Data ) 初始化受保護的內(nèi)存(de
bug 版在動態(tài)分配內(nèi)存的前后加入保護內(nèi)存以防止越界訪問),其中括號中的詞是微軟建
議的助記詞。這樣做的好處是這些值都很大,作為指針是不可能的(而且 32 位系統(tǒng)中指
針很少是奇數(shù)值,在有些系統(tǒng)中奇數(shù)的指針會產(chǎn)生運行時錯誤),作為數(shù)值也很少遇到,
而且這些值也很容易辨認,因此這很有利于在 Debug 版中發(fā)現(xiàn) Release 版才會遇到的錯
誤。要特別注意的是,很多人認為編譯器會用 0 來初始化變量,這是錯誤的(而且這樣很
不利于查找錯誤)。
??? (2) 通過函數(shù)指針調(diào)用函數(shù)時,會通過檢查棧指針驗證函數(shù)調(diào)用的匹配性。(防止原
形不匹配)
??? (3) 函數(shù)返回前檢查棧指針,確認未被修改。(防止越界訪問和原形不匹配,與第二
項合在一起可大致模擬幀指針省略 FPO )

??? 通常 /GZ 選項會造成 Debug 版出錯而 Release 版正常的現(xiàn)象,因為 Release 版中
未初始化的變量是隨機的,這有可能使指針指向一個有效地址而掩蓋了非法訪問。

除此之外,/Gm /GF 等選項造成錯誤的情況比較少,而且他們的效果顯而易見,比較容易
發(fā)現(xiàn)。

三、怎樣“調(diào)試” Release 版的程序

??? 遇到 Debug 成功但 Release 失敗,顯然是一件很沮喪的事,而且往往無從下手。如
果你看了以上的分析,結合錯誤的具體表現(xiàn),很快找出了錯誤,固然很好。但如果一時找
不出,以下給出了一些在這種情況下的策略。

??? 1. 前面已經(jīng)提過,Debug 和 Release 只是一組編譯選項的差別,實際上并沒有什么
定義能區(qū)分二者。我們可以修改 Release 版的編譯選項來縮小錯誤范圍。如上所述,可以
把 Release 的選項逐個改為與之相對的 Debug 選項,如 /MD 改為 /MDd、/O1 改為 /Od
,或運行時間優(yōu)化改為程序大小優(yōu)化。注意,一次只改一個選項,看改哪個選項時錯誤消
失,再對應該選項相關的錯誤,針對性地查找。這些選項在 Project\Settings... 中都可
以直接通過列表選取,通常不要手動修改。由于以上的分析已相當全面,這個方法是最有
效的。

??? 2. 在編程過程中就要時常注意測試 Release 版本,以免最后代碼太多,時間又很緊

??? 3. 在 Debug 版中使用 /W4 警告級別,這樣可以從編譯器獲得最大限度的錯誤信息,
比如 if( i =0 )就會引起 /W4 警告。不要忽略這些警告,通常這是你程序中的 Bug 引起
的。但有時 /W4 會帶來很多冗余信息,如 未使用的函數(shù)參數(shù) 警告,而很多消息處理函數(shù)
都會忽略某些參數(shù)。我們可以用
????? #progma warning(disable: 4702) //禁止
????? //...
????? #progma warning(default: 4702) //重新允許
來暫時禁止某個警告,或使用
????? #progma warning(push, 3) //設置警告級別為 /W3
????? //...
????? #progma warning(pop) //重設為 /W4
來暫時改變警告級別,有時你可以只在認為可疑的那一部分代碼使用 /W4。

??? 4.你也可以像 Debug 一樣調(diào)試你的 Release 版,只要加入調(diào)試符號。在 Project/S
ettings... 中,選中 Settings for "Win32 Release",選中 C/C++ 標簽,Category 選
?General,Debug Info 選 Program Database。再在 Link 標簽 Project options? 最后
加上 "/OPT:REF" (引號不要輸)。這樣調(diào)試器就能使用 pdb 文件中的調(diào)試符號。但調(diào)試時
你會發(fā)現(xiàn)斷點很難設置,變量也很難找到——這些都被優(yōu)化過了。不過令人慶幸的是,Ca
ll Stack 窗口仍然工作正常,即使幀指針被優(yōu)化,棧信息(特別是返回地址)仍然能找到
。這對定位錯誤很有幫助。

posted @ 2006-12-09 14:28 平凡的天才 閱讀(2339) | 評論 (1)編輯 收藏

在C/C++語言中,將一個組合數(shù)據(jù)類型如結構各個字段的值復制到另一個相同類型的結構中,可以將其對應字段賦值。這種方法對于各種復雜的結構如多字段結構、嵌套結構,就要寫很多行賦值語句,而且如果原來的結構定義更改,程序代碼就要隨著更改,使用很不方便。本文給出了一個通用的結構復制函數(shù)。
????????假定結構的類型為STRUCT_TYPE。為了提高效率,用指針引入兩個結構到函數(shù)中;為了通用,這兩個指針用任意指針。函數(shù)設計的出發(fā)點是,每個結構在內(nèi)存中各字段連續(xù)存放,而且,每個字段可以分解中一個一個的字節(jié)。這樣,復制結構時,可以讓兩個結構的對應的每個字節(jié)表示的值相等。于是,函數(shù)設計如下:


??void?struct_copy(
????void?*p_struct1,???/*結構指針1*/
????void?*p_struct2,???/*結構指針2*/
????unsigned?int?struct_size???/*結構類型長度,可以用sizeof(STRUCT_TYPE)代入*/
?????)
????{
?int?count=0;
?char?*p_char1,*p_char2;
?
?p_char1=(char?*)p_struct1;
?p_char2=(char?*)p_struct2;
?
?while(count!=struct_size)
?{
??*p_char1=*p_char2;
??p_char1++;
??p_char2++;
??count++;
?}
????}
這個函數(shù)在PC機和康柏ALPHA小型機上使用效果不錯。
????????有了這個函數(shù),如有類型同為STRUCT_TYPE的兩個結構struct1和struct2,要使struct1各字段的值與struct2各字段的值相等,也就是要把struct2各字段的值賦給struct1,就可以這樣調(diào)用以上函數(shù):?struct_copy(&struct1,?&struct2,?sizeof(STRUCT_TYPE));??????
????????以上函數(shù)簡單、通用、有效,對任意結構類型有效,也適合于其它復雜數(shù)據(jù)類型,如聯(lián)合(union)等。有趣的是,它也適合與整形、浮點型等簡單數(shù)據(jù)類型的變量之間復制。
????????此函數(shù)的設計思想可以運用在很多方面,如進程之間、計算機之間通信時,可以在通信的一方將某些數(shù)據(jù)類型拆分成字節(jié),到達通信的另一方再將收到的字節(jié)拼成相應的數(shù)據(jù)類型,這比按位傳遞要簡單、高效得多。

posted @ 2006-11-29 19:31 平凡的天才 閱讀(1542) | 評論 (9)編輯 收藏

SetLayeredWindowAttributes函數(shù):
hwnd是透明窗體的句柄,
crKey為顏色值,
bAlpha是透明度,取值范圍是[0,255],
dwFlags是透明方式,可以取兩個值:???????? 當取值為LWA_ALPHA時,crKey參數(shù)無效,bAlpha參數(shù)有效;???????? 當取值為LWA_COLORKEY時,bAlpha參數(shù)有效而窗體中的所有顏色為crKey的地方將變?yōu)橥该鳌??????? LWA_ALPHA = 0x2??????? LWA_COLORKEY=0x1 要使使窗體擁有透明效果,首先要有WS_EX_LAYERED擴展屬性 (舊的sdk沒有定義這個屬性,所以可以直接指定為0x80000). WS_EX_LAYERED = 0x80000

posted @ 2006-11-28 21:48 平凡的天才 閱讀(12064) | 評論 (2)編輯 收藏

/*相信這個算法是天才做出來的*/
#include <stdio.h>
#include <conio.h>


int main(int argc, char *argv[])
{
?int a[10]={125,26,35,24,548,256,25,298,7852,11},i,max[2];
?max[0]=max[1]=-32767;
?for(i=0;i<10;i++)
?{
??if(max[0]<a[i])
??{
???max[1]=max[0];
???max[0]=a[i];
??}
??else
??{
???if(max[1]<a[i])
???{
????max[1]=a[i];
???}
??}
?}
?for(i=0;i<10;i++)
?{
??printf("%d ",a[i]);
?}
?printf("\n");
?printf("max[0]=%d\n",max[0]);
?printf("max[1]=%d\n",max[1]);
?getch();?
?return 0;
}

posted @ 2006-11-24 20:15 平凡的天才 閱讀(1897) | 評論 (9)編輯 收藏

經(jīng)過千辛萬苦,我終于開博客了
剛來給個規(guī)范吧


VC編程規(guī)范
1.?基本要求
1.1?程序結構清析,簡單易懂,單個函數(shù)的程序行數(shù)不得超過100行。
1.2?打算干什么,要簡單,直接了當,代碼精簡,避免垃圾程序。
1.3?盡量使用標準庫函數(shù)和公共函數(shù)。
1.4?不要隨意定義全局變量,盡量使用局部變量。
1.5?使用括號以避免二義性。

2.可讀性要求
2.1?可讀性第一,效率第二。
2.2?保持注釋與代碼完全一致。
2.3?每個源程序文件,都有文件頭說明,說明規(guī)格見規(guī)范。
2.4?每個函數(shù),都有函數(shù)頭說明,說明規(guī)格見規(guī)范。
2.5?主要變量(結構、聯(lián)合、類或?qū)ο螅┒x或引用時,注釋能反映其含義。
2.7?常量定義(DEFINE)有相應說明。
2.8?處理過程的每個階段都有相關注釋說明。
2.9?在典型算法前都有注釋。
2.10?利用縮進來顯示程序的邏輯結構,縮進量一致并以Tab鍵為單位,定義Tab為?6個
字節(jié)。
2.11?循環(huán)、分支層次不要超過五層。
2.12?注釋可以與語句在同一行,也可以在上行。
2.13?空行和空白字符也是一種特殊注釋。
2.14?一目了然的語句不加注釋。
2.15?注釋的作用范圍可以為:定義、引用、條件分支以及一段代碼。
2.16?注釋行數(shù)(不包括程序頭和函數(shù)頭說明部份)應占總行數(shù)的?1/5?到?1/3?。

3.?結構化要求
3.1?禁止出現(xiàn)兩條等價的支路。
3.2?禁止GOTO語句。
3.3?用?IF?語句來強調(diào)只執(zhí)行兩組語句中的一組。禁止?ELSE?GOTO?和?ELSE?RETURN。
3.4?用?CASE?實現(xiàn)多路分支。
3.5?避免從循環(huán)引出多個出口。
3.6?函數(shù)只有一個出口。
3.7?不使用條件賦值語句。
3.8?避免不必要的分支。
3.9?不要輕易用條件分支去替換邏輯表達式。

4.?正確性與容錯性要求
4.1?程序首先是正確,其次是優(yōu)美
4.2?無法證明你的程序沒有錯誤,因此在編寫完一段程序后,應先回頭檢查。
4.3?改一個錯誤時可能產(chǎn)生新的錯誤,因此在修改前首先考慮對其它程序的影響。
4.4?所有變量在調(diào)用前必須被初始化。
4.5?對所有的用戶輸入,必須進行合法性檢查。
4.6?不要比較浮點數(shù)的相等,
如:?10.0?*?0.1?==?1.0?,?不可靠
4.7?程序與環(huán)境或狀態(tài)發(fā)生關系時,必須主動去處理發(fā)生的意外事件,如文件能否
邏輯鎖定、打印機是否聯(lián)機等。
4.8?單元測試也是編程的一部份,提交聯(lián)調(diào)測試的程序必須通過單元測試。

5.?可重用性要求

5.1?重復使用的完成相對獨立功能的算法或代碼應抽象為公共控件或類。
5.2?公共控件或類應考慮OO思想,減少外界聯(lián)系,考慮獨立性或封裝性。
5.3?公共控件或類應建立使用模板。

附:C++?編程規(guī)范,delphi作相應的參考

.1適用范圍

本標準適用于利用Visul?C++?,Borland?C++進行軟件程序開發(fā)的人員.。

.2變量命名

命名必須具有一定的實際意義,形式為xAbcFgh,x由變量類型確定,Abc、Fgh表示連續(xù)意
義字符串,如果連續(xù)意義字符串僅兩個,可都大寫.如OK.

具體例程:

BOOL類型?bEnable;
ch?*?char?chText
c?*?類對象?cMain(對象實例)
h?*?Handle(句柄)?hWnd
i?*?int
n?*?無符號整型
p?*?指針
sz,str?*?字符串
w?WORD
x,y?坐標

Char或者TCHAR類型?與Windows?API有直接聯(lián)系的用szAppName[10]形式否則用
FileName[10]形式,單個字符也可用小寫字母表示;

Int類型?nCmdShow;
LONG類型?lParam;
UINT類型?uNotify;?
DWORD類型?dwStart;
PSTR類型?pszTip;
LPSTR類型?lpCmdLine
LPTSTR類型?lpszClassName;
LPVOID類型?lpReserved
WPARAM類型?wParam,
LPARAM類型?lParam
HWND類型?hDlg;
HDC類型?hDC;
HINSTANCE類型?hInstance
HANDLE類型?hInstance,
HICON類型?hIcon;
int?iTmp
float?fTmp
DWORD?dw*
String?,?AnsiString?str?*
m_?類成員變量?m_nVal,?m_bFlag
g_?全局變量?g_nMsg,?g_bFlag

局部變量中可采用如下幾個通用變量:nTemp,nResult,I,J(一般用于循環(huán)變量)。
其他資源句柄同上

.3常量命名和宏定義
常量和宏定義必須具有一定的實際意義;
常量和宏定義在#include和函數(shù)定義之間;
常量和宏定義必須全部以大寫字母來撰寫,中間可根據(jù)意義的連續(xù)性用下劃線連接,每一
條定義的右側必須有一簡單的注釋,說明其作用;
資源名字定義格式:
菜單:IDM_XX或者CM_XX
位圖:IDB_XX
對話框:IDD_XX
字符串:IDS_XX
DLGINIT:DIALOG_XX
ICON:IDR_XX

.4函數(shù)命名
函數(shù)原型說明包括引用外來函數(shù)及內(nèi)部函數(shù),外部引用必須在右側注明函數(shù)來源:?模
塊名及文件名,?如是內(nèi)部函數(shù),只要注釋其定義文件名;
第一個字母必須使用大寫字母,要求用大小寫字母組合規(guī)范函數(shù)命名,必要時可用下劃線
間隔,示例如下:
void?UpdateDB_Tfgd?(TRACK_NAME);?//Module?Name?:r01/sdw.c
void?PrintTrackData?(TRACK_NAME);?//Module?Name?:r04/tern.c
void?ImportantPoint?(void);?//Module?Name?:r01/sdw.c
void?ShowChar?(int?,?int?,?chtype);?//Local?Module
void?ScrollUp_V?(int?,?int);?//Local?Module
.5結構體命名
結構體類型命名必須全部用大寫字母,原則上前面以下劃線開始;結構體變量命名必須用
大小寫字母組合,第一個字母必須使用大寫字母,必要時可用下劃線間隔。對于私有數(shù)
據(jù)區(qū),必須注明其所屬的進程。全局數(shù)據(jù)定義只需注意其用途。

示例如下:
typedef?struct
{
char?szProductName[20];
char?szAuthor[20];
char?szReleaseDate[16];
char?szVersion[10];?
unsigned?long?MaxTables;
unsigned?long?UsedTables;
}DBS_DATABASE;
DBS_DATABASE?GdataBase;

6?控件的命名:
用小寫前綴表示類別
用小寫前綴表示類別:
fm?窗口
cmd?按鈕
cob?combo,下拉式列表框
txt?文本輸入框
lab?labal,標簽
img?image,圖象
pic?picture
grd?Grid,網(wǎng)格
scr?滾動條
lst?列表框
frm?fram

7注釋
原則上注釋要求使用中文;
文件開始注釋內(nèi)容包括:公司名稱、版權、作者名稱、時間、模塊用途、背景介紹等,復
雜的算法需要加上流程說明;
函數(shù)注釋包括:輸入、輸出、函數(shù)描述、流程處理、全局變量、調(diào)用樣例等,復雜的函數(shù)
需要加上變量用途說明;
程序中注釋包括:修改時間和作者、方便理解的注釋等;
引用一:?文件開頭的注釋模板
/******************************************************************

**?文件名:
**?Copyright?(c)?1998-1999?*********公司技術開發(fā)部
**?創(chuàng)建人:
**?日?期:
**?修改人:
**?日?期:
**?描?述:
**
**?版?本:
**--------------------------------------------------------------------------
---
******************************************************************/
引用二:?函數(shù)開頭的注釋模板
/*****************************************************************

**?函數(shù)名:
**?輸?入:?a,b,c
**?a---
**?b---
**?c---
**?輸?出:?x---
**?x?為?1,?表示...
**?x?為?0,?表示...
**?功能描述:
**?全局變量:
**?調(diào)用模塊:
**?作?者:
**?日?期:
**?修?改:
**?日?期:
**?版本
****************************************************************/
引用三:?程序中的注釋模板
/*----------------------------------------------------------*/
/*?注釋內(nèi)容?*/
/*----------------------------------------------------------*/
8?程序
a.?程序編碼力求簡潔,結構清晰,避免太多的分支結構及太過于技巧性的程序,
盡量不采用遞歸模式。
b.?編寫程序時,亦必須想好測試的方法,換句話說,”單元測試”?的測試方案應
在程序編寫時一并擬好。
c.?注釋一定要與程序一致。
d.?版本封存以后的修改一定要將老語句用/*?*/?封閉,不能自行刪除或修改,并要
在文件及函數(shù)的修改記錄中加以記錄。
e.?程序中每個block?的開頭?”{"?及?"}”?必須對齊,嵌套的block?每進一套,
縮進一個tab,TAB?為4個空格,block類型包括if、for、while、do等關鍵字引出的。
f.?對于比較大的函數(shù),每個block?和特殊的函數(shù)調(diào)用,都必須注明其功能,舉例如下

count.divisor?=?1193280?/?freq;?//?compute?the?proper?count
OutByte((unsigned?short)67,?(unsigned?char)182);?//?tell?8253?that?a
count?is?coming
OutByte((unsigned?short)66,?count.?c[0]);?//?send?low-order?byte
OutByte((unsigned?short)66,?count.?c[1]);?//?send?high-order?byte
×××××××××××××××××××××××××××××××××××××××

bcb,delphi中的變量命名:
遵循匈牙利命名法,命
名必須有意義,制定如下規(guī)定
窗體:?以大寫的W開始,如About版權窗體,?命名為WAbout
文件:以大寫的F開始,如About版權窗體,文件命名為FAbout.cpp
按鈕(Button):如退出按鈕,命名為btnExit

基類:?加base標記,如報表基類,窗體命名為:WBaseRep,?文件命名為FBaseRep.cpp?

posted @ 2006-11-24 17:52 平凡的天才 閱讀(2245) | 評論 (2)編輯 收藏

僅列出標題
共2頁: 1 2 
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            久久综合亚洲社区| 欧美承认网站| 亚洲一区在线看| 国产精品swag| 欧美亚洲一区二区三区| 一本色道久久精品| 国产欧美精品在线| 久久在线精品| 欧美高清视频在线| 午夜精品久久久久久久男人的天堂| 亚洲理论在线观看| 亚洲欧美另类久久久精品2019| 国产乱码精品一区二区三区五月婷 | 亚洲理伦在线| 国产精品亚洲精品| 免费看精品久久片| 欧美日韩国产bt| 欧美一区二区三区播放老司机| 欧美一级专区| 最新亚洲一区| 亚洲综合第一| 亚洲黄网站黄| 亚洲综合视频一区| 亚洲人体一区| 亚洲丝袜av一区| 在线看欧美视频| 一本色道久久综合亚洲精品按摩| 国产婷婷一区二区| 欧美激情一区在线| 国产精品午夜国产小视频| 欧美成人精品影院| 国产精自产拍久久久久久| 欧美激情一区二区| 国产欧美日韩| 日韩一级视频免费观看在线| 黄色成人片子| 在线视频你懂得一区| 亚洲大片免费看| 亚洲欧美日本日韩| 一区二区欧美精品| 玖玖国产精品视频| 欧美一区二区高清| 欧美日韩亚洲国产精品| 六月天综合网| 国产一区在线免费观看| 亚洲最新视频在线| 日韩一区二区精品在线观看| 久久精品水蜜桃av综合天堂| 午夜精品视频在线观看| 欧美精品尤物在线| 免费亚洲网站| 国内久久婷婷综合| 亚洲女人小视频在线观看| 一本色道久久综合亚洲精品不卡 | 亚洲欧美国产一区二区三区| 中文网丁香综合网| 欧美喷潮久久久xxxxx| 你懂的国产精品永久在线| 国产一区二区精品丝袜| 亚洲综合不卡| 欧美一区网站| 国产女同一区二区| 亚洲一级黄色片| 亚洲欧美国产高清va在线播| 欧美午夜视频| 亚洲一区久久| 欧美中文在线视频| 国产一区二区观看| 欧美伊人久久大香线蕉综合69| 亚洲女人av| 国产人成一区二区三区影院| 香蕉视频成人在线观看| 久久久精品性| 欧美精品在线免费播放| 欧美激情精品| 亚洲免费高清| 欧美特黄一级| 欧美一区二区三区免费看 | 在线精品视频一区二区三四| 久久午夜精品| 亚洲国产合集| 亚洲网友自拍| 国产日韩欧美高清| 久久免费国产| 亚洲人妖在线| 欧美一级大片在线观看| 国产一区二区三区久久悠悠色av| 久久久精品一品道一区| 欧美激情偷拍| 亚洲影视综合| 一区免费观看| 欧美日韩激情小视频| 亚洲男人第一av网站| 另类春色校园亚洲| 一区二区三区 在线观看视| 国产精品高潮呻吟久久| 欧美一区二区三区在线免费观看| 久久综合成人精品亚洲另类欧美| 亚洲毛片av在线| 国产精品自拍在线| 欧美大片在线影院| 一区二区三区四区蜜桃| 久久噜噜噜精品国产亚洲综合| 亚洲人午夜精品| 国产欧美高清| 欧美人成在线视频| 久久久久国内| 亚洲午夜日本在线观看| 欧美成人亚洲| 久久精品视频播放| 宅男噜噜噜66一区二区| 在线观看一区二区精品视频| 欧美三级电影一区| 卡一卡二国产精品| 亚洲欧美日韩成人| 99视频精品| 亚洲国产精品视频一区| 久久精品最新地址| 亚洲一区自拍| 亚洲精品字幕| 亚洲风情亚aⅴ在线发布| 国产精品久久久久影院亚瑟| 免费h精品视频在线播放| 亚洲欧美bt| 99热免费精品在线观看| 亚洲高清资源| 免费在线观看日韩欧美| 久久爱另类一区二区小说| 亚洲社区在线观看| 亚洲剧情一区二区| 亚洲国产精品成人一区二区| 国产婷婷97碰碰久久人人蜜臀| 欧美日韩在线不卡一区| 欧美成人69av| 美女精品网站| 久久久久成人精品免费播放动漫| 午夜精品网站| 亚洲欧美国产精品va在线观看 | 99热精品在线观看| 亚洲成人在线视频播放 | 亚洲精品国精品久久99热| 免费久久99精品国产自在现线| 校园春色综合网| 亚洲欧美日韩视频二区| 亚洲永久免费视频| 亚洲一区二区三区激情| 一本色道久久综合狠狠躁篇的优点| 亚洲精品久久久蜜桃| 亚洲精品在线一区二区| 日韩视频精品在线| 夜色激情一区二区| 99精品国产福利在线观看免费| 欧美在线国产| 午夜精品久久久久久久蜜桃app| 日韩亚洲视频| 亚洲无毛电影| 亚洲欧美日韩综合| 久久超碰97中文字幕| 久久一二三国产| 欧美高清在线| 欧美日韩一区综合| 国产精品午夜国产小视频| 国产一区av在线| 亚洲高清视频一区| 99ri日韩精品视频| 亚洲女与黑人做爰| 久久人人爽人人| 欧美激情精品久久久久久变态| 亚洲精品一区二区三区av| 亚洲深夜福利视频| 欧美在线短视频| 欧美成年人视频| 国产精品免费观看视频| 怡红院av一区二区三区| 一区二区三区日韩欧美精品| 欧美一区二区三区四区在线| 久久久人成影片一区二区三区观看| 亚洲国产毛片完整版| 欧美一区国产在线| 麻豆精品精华液| 一区二区电影免费观看| 欧美一区二区国产| 欧美精品久久一区| 国产亚洲精品久| 99国产精品国产精品久久| 欧美一级大片在线观看| 亚洲国内欧美| 欧美亚洲午夜视频在线观看| 欧美高清视频一区二区| 国产在线精品一区二区中文| 一区二区高清在线| 牛牛国产精品| 性色av香蕉一区二区| 欧美日本在线观看| 在线观看国产精品网站| 亚洲免费在线观看| 亚洲国产日韩在线| 久久久免费精品| 国产欧美午夜| 亚洲女优在线|