【程式四】:
'看看我們的東西被拷貝到哪兒去了
Sub TestCopyMemory()
Dim i As Long, k As Long
k = 5
i = VarPtr(k)
NOTE4: CopyMemory i, 40000, 4
Debug.Print k
Debug.Print i
i = VarPtr(k)
NOTE5: CopyMemory ByVal i, 40000, 4
Debug.Print k
End Sub
程式輸出:
5
40000
40000
由於NOTE4處使用缺省的ByVal,傳遞的是i的位址(也就是指向i的指標),所以常量40000拷貝到了變數i堙A因此i的值成了40000,而k的值卻沒有變化。
但是,在NOTE4前有:i=VarPtr(k),本意是要把i本身做為一個指標來使用。
這時,我們必須如NOTE5那樣用ByVal來傳遞指標i,由於i是指向變數k的指標,所以最後常量40000被拷貝了變數k堙C
希望你已經理解了這種區別,在後面問題的討論中,我還會再談到它。
4、AddressOf
它用來得到一個指向VB函數入口位址的指標,不過這個指標只能傳遞給API使用,以使得API能回調VB函數。
本文不準備詳細討論函數指標,關於它的使用請參考VB文檔。
5、拿來主義
實際上,有了CopyMemory,VarPtr,AddressOf這三把斧頭,我們已經可以將C堸禰貌澈標操作拿過來了。
如下面的C程式包括了大部分基本的指標指標操作:
struct POINT{
int x; int y;
};
int Compare(void* elem1, void* elem2){}
void PtrDemo(){
//指針聲明:
char c = 'X'; //聲明一個char型變數
char* pc; long* pl; //聲明普通指針
POINT* pPt; //聲明結構指標
void* pv; //聲明無類型指針
int (*pfnCastToInt)(void *, void*);//聲明函數指標:
//指針賦值:
pc = &c; //將變數c的位址值賦給指針pc
pfnCompare = Compare; //函數指標賦值。
//指針取值:
c = *pc; //將指標pc所指處的記憶體值賦給變數c
//用指針賦值:
*pc = 'Y' //將'Y'賦給指標pc所指記憶體變數堙C
//指標移動:
pc++; pl--;
}
這些對指針操作在VB堻ㄕ陬它P的東西,前面討論ByVal和ByRef時曾說過傳指針和傳地址是一回事,
實際上當我們在VB堨巹坌椌ByRef聲明函數參數時,我們已經就聲明了指標。
如一個C聲明的函數:long Func(char* pc)
其對應的VB聲明是:Function Func(pc As Byte) As Long
這時參數pc使用缺省的ByRef傳位址方式來傳遞,這和C堨峆針來傳遞參數是一樣。
那麼怎麼才能象C堥獐邥確地聲明一個指標呢?
很簡單,如前所說,用一個32位元長整數來表達指標就行。在VB奡N是用Long型來明確地聲明指標,我們不用區分是普通指標、
無類型指標還是函數指標,通通都可用Long來聲明。而給一個指標賦值,就是賦給它用VarPar得到的另一個變數的位址。具體見程式五。
【程式五】:同C一樣,各種指針。
Type POINT
X As Integer
Y As Integer
End Type
Public Function Compare(elem1 As Long, elem2 As Long) As Long
'
End Function
Function FnPtrToLong(ByVal lngFnPtr As Long) As Long
FnPtrToLong = lngFnPtr
End Function
Sub PtrDemo()
Dim l As Long, c As Byte, ca() As Byte, Pt As POINT
Dim pl As Long, pc As Long, pv As Long, pPt As Long, pfnCompare As Long
c = AscB("X")
pl = VarPtr(l) '對應C堛long、int型指針
pc = VarPtr(c) '對應char、short型指針
pPt = VarPtr(Pt) '結構指標
pv = VarPtr(ca(0)) '位元組陣列指標,可對應任何類型,也就是void*
pfnCompare = FnPtrToLong(AddressOf Compare) '函數指標
CopyMemory c, ByVal pc, LenB(c) '用指針取值
CopyMemory ByVal pc, AscB("Y"), LenB(c) '用指針賦值
pc = pc + LenB(c) : pl = pl - LenB(l) '指標移動
End Sub
我們看到,由於VB不直接支持指標操作,在VB堨峆標取值和用指標賦值都必須用CopyMemory這個API,
而調用API的代價是比較高的,這就決定了我們在VB堥洏峆標不能象在C堥獐辿菪悕M頻繁,我們必須要考慮指標操作的代價,
在後面的"指標應用"我們會再變談這個問題。
程式五中關於函數指標的問題請參考VB文檔,無類型指標void*會在下面"關於Any的問題"婸﹛C
程式五基本上已經包括了我們能在VB媔i行的所有指標操作,僅此而已。
下面有一個小測試題,如果現在你就弄懂了上面程咬金的三板斧,你就應該能做得出來。
上面提到過,VB.NET中沒有VarPtr,我們可以用聲明API的方式來引入MSVBVM60.DLL中的VarPtr。
現在的問題如果不用VB的運行時DLL檔,你能不能自己實現一個ObjPtr。答案在下一節後給出。
|