設(shè)為首頁收藏本站Access中國

Office中國論壇/Access中國論壇

 找回密碼
 注冊

QQ登錄

只需一步,快速開始

tag 標(biāo)簽: FreeBasic入門

相關(guān)帖子

版塊 作者 回復(fù)/查看 最后發(fā)表

沒有相關(guān)內(nèi)容

相關(guān)日志

分享 freebasic菜鳥初學(xué)Freebasic基礎(chǔ)教程十二:使用afx庫的數(shù)組、字典和com庫
ganlinlao 2017-5-15 21:00
一、使用safeArray數(shù)組 我很驚訝jose為什么要提供vb數(shù)組safeArray,而且他對提供vb數(shù)組走了極端,分別提供了極其精簡只限wstring類型的CwstrArray,和全功能的variant類型的CvariantArray。但想一想,也許這樣子也有一定的好處,在多線程的模式下,還有比safeArray數(shù)組更好的數(shù)組嗎?畢竟這是線程安全的,而且又易于使用。 提供CwstrArray字符串?dāng)?shù)組,是因為spit函數(shù),必須有一個字符串?dāng)?shù)組來接收spit分割后字符串。不過在某些情況下,我們也是可以直接使用CwstrArray數(shù)組。如果要有VB交互的話,可以使用CvariantArray數(shù)組,但如果純粹在FB下使用,沒必要使用Variant和variant數(shù)組,那是在找虐。 cWstrArray數(shù)組和vb中使用數(shù)組還是有細微的差別。 (1)、vb中dim arr(4) as string,其中4表示數(shù)組的ubound是4,這樣的數(shù)組其實是5個元素。 但CwstrArray(4)表示這個數(shù)組是4個元素,它的Ubound是3 (2) vb可以直接使用 arr(0)="這是一個測試",但cwstrArray.item(0)="這是一個測試",這個item無法省略 (3)在單線程模式下,不必擔(dān)心數(shù)組是不是會lock,但在多線程模式下,你要注意數(shù)組加解鎖問題,也就是accessData和UaccessData這兩個方法最好是明確使用。 (4)字符串聯(lián)接用+號,盡量不使用,如果號,你得注意是**CwstrArray.item(0),2個*號,這個同樣適用于Cwstr類中,使用聯(lián)接號必須使用 **cwstr,使用+號沒有任何問題,原因是因為符號得先強制轉(zhuǎn)換數(shù)據(jù)類型,先cast(),再進行拼接。 (5)vb中獲得數(shù)組元素的數(shù)量,是ubound(Arr)-Lbound(Arr),但CwstrArray使用是CwstrArray.count直接返回元素數(shù)量 (6)cWstrArray數(shù)組中可以復(fù)制數(shù)組,可以嵌套數(shù)組,可以使用variant中的數(shù)組vt_Array(僅限于字符串類型數(shù)組) #include once "afx/cwstrArray.inc" #include once "afx/cwindow.inc" dim myArr as cwstrArray=cwstrArray(4) myArr.item(0)="1" myArr.item(1)="2" myArr.item(2)="3" myArr.item(3)="4" myarr.sort(false) 'false是降序,默認是true是升序 'afxmsg "one = " myarr.item(0) "two= " myArr.item(1) "Three= " myArr.item(2) "four=" myArr.item(3) afxmsg "one = " + myarr.item(0) + "two= " + myArr.item(1) + "Three= " + myArr.item(2) + "four=" + myArr.item(3) 二、使用字典dictionary afx庫中也分別提供了wstring類型的dictionary和variant類型的dictionary。用法和VB中使用dictionary幾乎一樣。 cwstrDic類比vb的dictionary多了一個count方法,返回一個字典元素的數(shù)量。 說實話,我對afx庫只提供dictionary,其實是非常失望的。一般最好使用mdtypes這個泛型的集合類庫。
個人分類: FreeBasic|4356 次閱讀|0 個評論
分享 freebasic菜鳥初學(xué)Freebasic基礎(chǔ)教程十一:使用afx庫有關(guān)字符串的函數(shù)和類
ganlinlao 2017-5-12 21:00
freebasic菜鳥初學(xué)Freebasic基礎(chǔ)教程十一:使用afx庫有關(guān)字符串的函數(shù)和類
'冬瓜湯編寫整理 字符串處理,對于大部分語言來說,都是一件麻煩的事,ansi,unicode,utf-8……,我前面已經(jīng)說過了,F(xiàn)B對于unicode支持不是特別的好,也就是wstring只能是指針或固定長度,而不是動態(tài)不定長的字符串,這非常麻煩。雖然wstr()可以快速將string字符串轉(zhuǎn)變成wstring字符串,但其實很多場合下的使用,還是非常不方便。afx的CWstr類就是專門處理unicode字符串,其實用它可以處理ansi,unicode,utf-8,Bstr(vbstring),非常方便,不管是網(wǎng)絡(luò)上常用的utf-8,還是com的BSTR,都挺方便的。 一、len(),和sizeof()對字符串的影響 在FB中,len()用來判斷一個字符串的大小, 對于string和zstring來說,len返回的是字節(jié)大小。對于unicode來說,len()返回的是字符數(shù)。uniocde字符串的字節(jié)大小,是len(unicode)*2 。 而sizeof()是用來判斷一個變量,對象內(nèi)存占用多少。 這是一個測試?yán)樱? #include once "afx/cwindow.inc" Dim As String anStr,anStrEN dim anStrU as string dim unStr as wstring*20 '這里直接用固定長度20個unicode字符 anStrEn = "FB is new basic" unstr = "FB是語言" anstr = "FB是語言" anStrU = wstr(anstr) afxmsg "ansi的Len大小:" Len( anstr) chr(13) _ "ansi的sizeof大。" sizeof(anstr) chr(13) _ "ansi純英文的Len大。" Len( anstrEn) chr(13) _ "ansi純英文的sizeof大。" sizeof(anstrEn) chr(13) _ "unicode的Len大。" len(unStr) chr(13) _ "uniocde的sizeof大小:" sizeof(unStr) chr(13) _ "an轉(zhuǎn)Un的len大。" len(anStrU) chr(13) _ "an轉(zhuǎn)Un的sizeof大。" sizeof(anStrU) chr(13) _ "wstr()返回值的Len大小:" len(wstr(anstr)) chr(13) _ "wstr()返回值的sizeof大。" sizeof(wstr(anStr)) 在這里我們會發(fā)現(xiàn)sizeof對于string不起作用,總是返回大小12,這我無法解釋,只能把它理解成因為string是一個動態(tài)不定長的字符串?dāng)?shù)組,sizeof返回的實際上是一個數(shù)組結(jié)構(gòu)的字節(jié)大小。如果用64位編譯,你會發(fā)現(xiàn)sizeof總是返回24。 (2)wstr(string)賦值給一個string類型的變量,不會發(fā)現(xiàn)任何變化。 (3) sizeof(wstr())總是返回0,估計是一個Null值。 所以在實際使用中如果要預(yù)先分配內(nèi)存的話,千萬要小心不要誤以為sizeof(string)能返回總字節(jié)大小。 '冬瓜湯整理編寫 二、使用afx的字符串函數(shù) #include once "afx/CWSTR.inc" #include once "afx/afxStr.inc" using afx ' 所有的afx庫,都處在同一個命名空間afx里,F(xiàn)B的命名空間規(guī)則和c#/vb.net是一樣的。 '我不喜歡using這個關(guān)鍵詞,我更喜歡Imports,但沒辦法 import在FB很早以前就是一個關(guān)鍵字了。 '判斷是否是數(shù)字 Dim inNumeric As boolean=afxIsNumeric("-1395.43") '同left的用法 Dim As cwstr strLeft=afxstrClipLeft("這是一個Freebasic測試",9) '同mid的用法 Dim As cwstr strMid=afxstrClipMid("這是一個Freebasic測試",4,5) '同Right用法 Dim As cwstr strRight=afxstrClipRight("這是一個Freebasic測試",2) '左右嵌入空格或指定的符號 Dim As cwstr strCset=afxstrCset("單身狗",11,"*") '返回 ****單身狗**** '刪除指定數(shù)量的子字符串 Dim As cwstr strDelete=afxstrDelete("這是一個Freebasic測試",4,9) '從主字符串提取匹配指定字符的字符串,但不包括指定字符本身 Dim As cwstr strExtract=afxstrExtract(1,"誰是單身狗,不是單身貓","狗") ' Dim As cwstr strExtractAny=afxstrExtractAny(1,"誰是單身狗,不是單身貓","貓狗") '從指定位置插入子字符串 Dim As cwstr strInsert=afxstrInsert("01032547891","—",3) '從第三個位置之后插入子字符串 '同join用法 Dim cwsa As cwstrArray=cwstrArray(4,1) '建一個4行1列的數(shù)組 cwsa.Item(1) = "One" cwsa.Item(2) = "Two" cwsa.Item(3) = "Three" cwsa.item(4)="Four" DIM strJoinAS CWSTR = AfxStrJoin(cwsa, ",") '用法和vb的join一樣 '左邊加入指定數(shù)量的空格或指定符號 DIM strLset AS CWSTR = AfxStrLSet("FreeBasic", 20, "#") '解析帶分隔符的字符串,分隔符可以多種混用 DIM cws AS CWSTR = AfxStrParse("one,two,three", 2) ' Returns "two" DIM cws AS CWSTR = AfxStrParseAny("1;2,3", 2, ",;") ' Returns "2" '解析帶分隔符的字符串,并返回數(shù)量 DIM nCount AS LONG = AfxStrParseCount("one,two,three", ",") ' Returns 3 DIM nCount AS LONG = AfxStrParseCountAny("1;2,3", ",;") ' Returns 3 '返回子字符串第一次出現(xiàn)在主字符串位置之前的那部分字符串,可以指定搜索位置從哪里開始,默認從1 DIM cws AS CWSTR = AfxStrRemain("Brevity is the soul of wit", "is ") ' Returns "the soul of wit" DIM cws AS CWSTR = AfxStrRemainAny("I think, therefore I am", ",") ' Returns "therefore I am" '從主字符串移除子符串 DIM cws AS CWSTR = AfxStrRemove(" ", "[]") ' Returns "Hello" DIM cws AS CWSTR = AfxStrRemoveAny("abacadabra", "bac") ' Returns "dr" '替換,同Replace() DIM cws AS CWSTR = AfxStrReplace("Hello World", "World", "Earth") ' Returns "Hello Earth" DIM cws AS CWSTR = AfxStrReplaceAny("abacadabra", "bac", "*") ' Returns "*****d**r* '去掉主字符串不匹配指定的子符串的那部分,只返回匹配的子符串或子符串組 DIM cws AS CWSTR = AfxStrRetain("abacadabra","b") ' Returns "bb" DIM cws AS CWSTR = AfxStrRetainAny("1234567890ak;lk;l1234567890", ";/p") ' Returns ";;" '反轉(zhuǎn)字符串 DIM cws AS CWSTR = AfxStrReverse("garden") ' Returns "nedrag" '右邊添加指定數(shù)量的空格或指定符號 DIM cws AS CWSTR = AfxStrRSet("FreeBasic", 20, "*") '將帶各種不規(guī)范分隔符的字符串,整理成一種規(guī)范的字符串 DIM cws AS CWSTR = AfxStrShrink(",,, one , two three, four,", " ,")' Returns "one two three four" '同split DIM cws AS CWSTR = "- This, a sample string." DIM cwsa AS CWstrArray = AfxStrSplit(cws, " ,.-") FOR i AS LONG = cwsa.LBound TO cwsa.UBound PRINT cwsa.Item(i) NEXT '統(tǒng)計子符串在主子符串出現(xiàn)的次數(shù) DIM nCount AS LONG = AfxStrTally("abacadabra", "ab") ' Returns 2 DIM nCount AS LONG = AfxStrTallyAny("abacadabra", "bac") ' Returns 8 '在開頭和結(jié)尾,刪除成對的字符符號 AfxStrUnWrap("Paul", "", "") results Paul AfxStrUnWrap("'Paul'", "'") results Paul '確定主字符串是否包含指定子符串中任一一個字符 DIM nCount AS LONG = AfxStrVerify(5, "123.65,22.5", "0123456789") ' Returns 7 '在字符串開頭和結(jié)尾添加 成對的字符 AfxStrWrap('保羅',"", "")結(jié)果保羅 ……還有一些函數(shù),具體看幫助文檔 ########################################################### 三、使用BSTR 為了方便使用,我將Cbstr類和Cwstr類合并在同一個文件cwstr.inc中 #include once "afx/Cwstr.inc" using afx Dim myBstr as CBSTR myBstr="這是一個測試" 用 Cbstr類,主要是為了能夠自動釋放vbstring指針。忘記釋放bstr指針,是非常容易犯的錯。所以一遇到任何傳進來的bstr字符串 就立即用cbstr進行接收。
個人分類: FreeBasic|4301 次閱讀|0 個評論
分享 Freebasic菜鳥初學(xué)Freebasic基礎(chǔ)教程九:了解com數(shù)據(jù)類型
ganlinlao 2017-5-11 10:34
FB在windows上使用,有兩種東西是無法回避的,一種是api,一種是com,這是幾乎所有在windows上使用的語言都必須用到的。 這是引用自csdn上的博客內(nèi)容: 了解一下com數(shù)據(jù)類型,有助于在FB中使用com。 BSTR、 BSTR到底是什么。 BSTR是COM中的數(shù)據(jù)類型,在COM編程時,接口中定義的字符串類型都是BSTR類型, 而使用BSTR類型是極其容易出錯的,同時,一不小心就有可能造成內(nèi)存泄露。所以有如下建議: 在對接口進行實現(xiàn)時,從接口參數(shù)中傳遞過來的BSTR類型的變量,一定要在第一時刻將BSTR類型轉(zhuǎn)變成_bstr_t類型的變量,就是因為 BSTR有隱藏的危險 ,同時當(dāng)使用BSTR出現(xiàn)bug時,而這種bug而不一定好找; 在對接口進行實現(xiàn)時,接口中的BSTR字符串參數(shù)是out時,在接口實現(xiàn)的內(nèi)部不要定義BSTR類型變量,而是定義_bstr_t類型的變量,進行操作,操作完成以后,然后在轉(zhuǎn)為BSTR類型的變量傳出去。 既然是這樣,就有人要問了,那么BSTR存在的必要是什么? 這個是由COM決定的,由于COM是跨系統(tǒng)及不同開發(fā)語言間實現(xiàn)互操作的技術(shù),常規(guī)以NULL結(jié)尾的簡單字符串在COM組件間傳遞不太方便。 所以,BSTR就這么出現(xiàn)了。 BSTR作為指針類型,標(biāo)準(zhǔn)的BSTR是一個有長度前綴和NULL結(jié)束符的OLECHAR數(shù)組。BSTR的前4個字節(jié)是一個 表示字符串長度的前綴。BSTR長度域的值是字符串的字節(jié)數(shù),但不包括字符串結(jié)束符。BSTR實際上包含的是Unicode串, 所以字符數(shù)是字節(jié)數(shù)的一半。 所以,在能不使用BSTR的情況下,就盡量不要使用BSTR類型,而是使用對應(yīng)的_bstr_t類型。為了處理BSTR,Microsoft提供了以下API供使用: BSTR SysAllocString ( const OLECHAR * psz ); INT SysReAllocString ( BSTR * pbstr , const OLECHAR * psz ); BSTR SysAllocStringLen ( const OLECHAR * strIn , UINTui ); INT SysReAllocStringLen ( BSTR * pbstr , constOLECHAR * psz , unsignedintlen ); void SysFreeString ( BSTR bstrString ); UINT SysStringLen ( BSTR ); UINT SysStringByteLen ( BSTR bstr ); BSTR SysAllocStringByteLen ( LPCSTRpsz , UINTlen ); 現(xiàn)在對以上的 API 逐一的進行講解和應(yīng)用,大家可以結(jié)合著 MSDN ,看這篇博文,至少 MSDN 講的比我這里更詳細。 SysAllocString 分配內(nèi)存,并創(chuàng)建 BSTR 字符串; SysReAllocString 重新分配內(nèi)存,并將第二個參數(shù)指定的 OLECHAR 同時放入新開辟的的內(nèi)存中; SysAllocStringLen 分配內(nèi)存,將第一個參數(shù)指定的字符串的前 ui (第二個參數(shù)指定的字符個數(shù))個數(shù)放入開辟的內(nèi)存中; SysReAllocStringLen ,經(jīng)過上面兩個 API 的講解,這個 API 的就不需要更多的講解了; SysFreeString 釋放由以上的 API 函數(shù)開辟的內(nèi)存; SysStringLen 表示的是 BSTR 的字符個數(shù); SysStringByteLen 獲得 BSTR 字符串表示的字節(jié)數(shù),也就是 BSTR 的前 4 個字節(jié)表示的內(nèi)容; SysAllocStringByteLen 使用的是 ANSI string 進行創(chuàng)建 BSTR 對象,盡量少用該 API 。 VARIANT VARIANT結(jié)構(gòu)體主要是使用在COM(組件對象模型)中用于傳遞參數(shù)使用, 它的存在主要是為了保持一個在COM參數(shù)傳遞方法的統(tǒng)一性,它幾乎包含了所有普通常用類型的數(shù)據(jù)類型的傳遞, 如整型,浮點型,布爾型等等,以及相應(yīng)類型的指針類型,如整型指針。 它的使用也比較方便。先來看看這個結(jié)構(gòu)體它的結(jié)構(gòu): typedef struct tagVARIANT { union { struct __tagVARIANT { VARTYPE vt; WORD wReserved1; WORD wReserved2; WORD wReserved3; union { LONGLONG llVal; LONG lVal; BYTE bVal; SHORT iVal; FLOAT fltVal; DOUBLE dblVal; VARIANT_BOOL boolVal; _VARIANT_BOOL bool; SCODE scode; CY cyVal; DATE date; BSTR bstrVal; IUnknown *punkVal; IDispatch *pdispVal; SAFEARRAY *parray; BYTE *pbVal; SHORT *piVal; LONG *plVal; LONGLONG *pllVal; FLOAT *pfltVal; DOUBLE *pdblVal; VARIANT_BOOL *pboolVal; _VARIANT_BOOL *pbool; SCODE *pscode; CY *pcyVal; DATE *pdate; BSTR *pbstrVal; IUnknown **ppunkVal; IDispatch **ppdispVal; SAFEARRAY **pparray; VARIANT *pvarVal; PVOID byref; CHAR cVal; USHORT uiVal; ULONG ulVal; ULONGLONG ullVal; INT intVal; UINT uintVal; DECIMAL *pdecVal; CHAR *pcVal; USHORT *puiVal; ULONG *pulVal; ULONGLONG *pullVal; INT *pintVal; UINT *puintVal; struct __tagBRECORD { PVOID pvRecord; IRecordInfo *pRecInfo; } __VARIANT_NAME_4; } __VARIANT_NAME_3; } __VARIANT_NAME_2; DECIMAL decVal; } __VARIANT_NAME_1; } VARIANT, *LPVARIANT, VARIANTARG, *LPVARIANTARG; 這個結(jié)構(gòu)體呢,有5個成員,分別是 VARTYPE vt ,WORD wReserved1,WORD wReserved2,WORD wReserved3,和最后一個共用體。 其中vt用以指明最后一個共用體中哪一個成員有效,wReserved1,wReserved2,wReserved3,這三個我們使用的時候不用管,系統(tǒng)保留, 最后一個共用體根據(jù)vt的提示,對相應(yīng)的成員進行值的存儲。我們從兩個不同的角度來理解,首先是使用VARIANT來存儲參數(shù), 首先是聲明一個這個結(jié)構(gòu)體的對象,然后對對象的vt進行賦值,它可接受的值是一個枚舉值,也就說只能在枚舉這個范圍內(nèi)取值, 比如我要用VARIANT傳遞一個整數(shù),現(xiàn)在我對vt的賦值為VT_INT,這樣就說明了我要使用這個結(jié)構(gòu)體中共用體的整型變量, 接著對INT變量進行賦值,賦我們要傳遞的值。這樣就完成VARIANT的傳遞,F(xiàn)在我們從另外一個角度來理解VARIANT, 剛才是我們對VARIANT對象進行賦值傳遞,現(xiàn)在我們是這個VARIANT對象的接收者,我們從參數(shù)中獲得這個對象之后, 我們首先檢查這個結(jié)構(gòu)體的vt成員,看它哪個類型的變量有效,比如就這個例子而言,檢查到vt的值是VT_INT, 因此,我直接去獲取這個結(jié)構(gòu)體中VT_INT所對應(yīng)的變量,獲取它的值。這樣,我們從傳遞到使用兩個角度來理解了VARIANT結(jié)構(gòu)體, 概括起來說,就是vt指明了我要傳遞的變量的類型,結(jié)構(gòu)體中共用體的成員用來存儲vt指明的類型的值。 下面來看看具體VARIANT結(jié)構(gòu)體是如何使用賦值的,首先是第一種方法: 首先我們聲明一個VARIANT結(jié)構(gòu)體的對象vr1,然后使用VariantInit函數(shù)對其進行初始化,它的作用就是對vt賦VT_EMPTY, 對別的變量值附空,否則就是一個隨機值,這個過程和我們聲明一個int變量一樣,如果聲明的時候不初始化,就是一個隨機值。 編程過程中,不管是指針還是什么變量,都應(yīng)該在聲明之后對其進行初始化。接著就是我賦VT_INT給vt, 這里的V_VT就是代表要對vr1結(jié)構(gòu)體中的vt成員進行幅值,接著對vr1中的INT成員賦值,這里的V_INT就是表示要對INT賦值, 因此這里有一個規(guī)律,就是V_,它的后面加成員類型就可以對相應(yīng)的成員賦值,而這里的成員類型有一個對照表,在文章的最后給出, 比如,我要對BSTR成員賦值,我就用V_BSTR。這時候,就可以使用vr1了,使用完成之后,我們應(yīng)該調(diào)用VariantClear函數(shù), 這個函數(shù)的作用就是將vt賦值為VT_EMPTY,以及釋放使用這個結(jié)構(gòu)體中的內(nèi)存中的內(nèi)容,如果是com對象,該函數(shù)是不會進行對象的release操作的, 不管怎么樣,我們都應(yīng)該在使用完了VARIANT結(jié)構(gòu)體之后,調(diào)用這個函數(shù)。 下面是第二種方法,原理和過程和地中方法類似,有一點微小的區(qū)別, 就是VARIANT結(jié)構(gòu)體的賦值上面來說,有點不同,如下: 接下來是字符串的操作,BSTR,我們不能直接將字符串傳遞一個VARIANT結(jié)構(gòu)體對象,而是要用到函數(shù)SysAllocString, 它的返回值就是一個BSTR,由它分配一個字符串,供VARIANT,對于為什么要這么做,可以自己查看MSDN COM的Automation那部分: 完成之后,我們還應(yīng)該調(diào)用SysFreeString來釋放由SysAllocString分配的內(nèi)存。 另外,我們可以在類型與變量的對照表中發(fā)現(xiàn),同一類型,對應(yīng)了兩種不同的變量,如,INT對應(yīng)了變量有intVal和pintVal,其實這很簡單,后者是指針性,如果要使用,說明我們賦值的對象是一個指針,如下: 最后給出類型與變量的對照表,如果是使用地中方法用V_加類型,就直接使用下表中VT_后的名稱就可以了: Member name Description VT_EMPTY Indicates that a value was not specified. VT_NULL Indicates a null value, similar to a null value in SQL. VT_I2 Indicates ashortinteger. VT_I4 Indicates alonginteger. VT_R4 Indicates afloatvalue. VT_R8 Indicates adoublevalue. VT_CY Indicates a currency value. VT_DATE Indicates a DATE value. VT_BSTR Indicates a BSTR string. VT_DISPATCH Indicates anIDispatchpointer. VT_ERROR Indicates an SCODE. VT_BOOL Indicates a Boolean value. VT_VARIANT Indicates a VARIANTfarpointer. VT_UNKNOWN Indicates anIUnknownpointer. VT_DECIMAL Indicates adecimalvalue. VT_I1 Indicates acharvalue. VT_UI1 Indicates abyte. VT_UI2 Indicates anunsignedshort. VT_UI4 Indicates anunsignedlong. VT_I8 Indicates a 64-bit integer. VT_UI8 Indicates an 64-bit unsigned integer. VT_INT Indicates an integer value. VT_UINT Indicates anunsignedinteger value. VT_VOID Indicates a C stylevoid. VT_HRESULT Indicates an HRESULT. VT_PTR Indicates a pointer type. VT_SAFEARRAY Indicates a SAFEARRAY. Not valid in a VARIANT. VT_CARRAY Indicates a C style array. VT_USERDEFINED Indicates a user defined type. VT_LPSTR Indicates a null-terminated string. VT_LPWSTR Indicates a wide string terminated bynullNothingnullptra null reference (Nothing in Visual Basic). VT_RECORD Indicates a user defined type. VT_FILETIME Indicates a FILETIME value. VT_BLOB Indicates length prefixed bytes. VT_STREAM Indicates that the name of a stream follows. VT_STORAGE Indicates that the name of a storage follows. VT_STREAMED_OBJECT Indicates that a stream contains an object. VT_STORED_OBJECT Indicates that a storage contains an object. VT_BLOB_OBJECT Indicates that a blob contains an object. VT_CF Indicates the clipboard format. VT_CLSID Indicates a class ID. VT_VECTOR Indicates a simple, counted array. VT_ARRAY Indicates aSAFEARRAYpointer. VT_BYREF Indicates that a value is a reference. VARIANT使用起來是很簡單的,但是有些問題,我們還必須要去注意: 建立VARIANT變量時,必須使用VariantInit進行初始化 ; 對于VT_UI1, VT_I2, VT_I4, VT_R4, VT_R8, VT_BOOL, VT_ERROR, VT_CY, VT_DECIMAL, 和VT_DATE這些類型, 數(shù)據(jù)的值是直接儲存在VARIANT結(jié)構(gòu)中的,當(dāng)VARIANT的類型發(fā)生變化時,指向這些數(shù)據(jù)的指針會變得無效。 例如: VARIANT varParam ; :: VariantInit ( varParam ); short iVal = 20 ; varParam . vt = VT_I2 ; varParam . iVal = iVal ; short * pVal = varParam . iVal ; varParam . vt = VT_I4 ; varParam . lVal = 200 ; 此時,*pVal指向的值與你期望的可能是不一樣的。 對于VT_BYREF | any type數(shù)據(jù)類型,而VARIANT只是擁有這些數(shù)據(jù)指向內(nèi)存的指針,而內(nèi)存的釋放需要由函數(shù)的調(diào)用者負責(zé)。 例如: VARIANT varParam ; :: VariantInit ( varParam ); int * p = new int ; * p = 10 ; varParam . vt = VT_BYREF | VT_I4 ; varParam . plVal = ( long *) p ; delete p ; // If you donnot delete the memory, this may cause memory leak 對于VT_BSTR類型,在VARIANT中的字符串必須要用SysAllocString進行分配內(nèi)存,當(dāng)釋放時,或者VARIANT的類型發(fā)生改變時, 都需要調(diào)用SysFreeString進行內(nèi)存釋放,否則就會發(fā)生內(nèi)存泄露; 對于VT_ARRAY | any type類型,這個規(guī)則和VT_BSTR是類似的,在VARIANT中的數(shù)組必須使用SafeArrayCreate進行開辟內(nèi)存空間, 然后必須使用SafeArrayDestroy進行內(nèi)存空間的釋放; 對于VT_DISPATCH和VT_UNKNOWN,我們考慮的更多的就是引用計數(shù)器的增加與減少了, 是的,在進行賦值時需要進行引用計數(shù)的增加,釋放時,則需要對應(yīng)的減少。 SAFEARRAY的使用 SAFEARRAY的主要目的是用于automation中的數(shù)組型參數(shù)的傳遞,我們都知道,在網(wǎng)絡(luò)環(huán)境中,數(shù)組是不能直接傳遞的, 所以我們必須將數(shù)組封裝成SAFEARRAY類型,這樣才能進行傳遞,在COM編程時,SAFEARRAY類型是可以存放在VARIANT類型中, 指定vt為VT_ARRAY|*或者VT_BYREF|VT_ARRAY。對于SAFEARRAY,說白了,就是普通的數(shù)組,添加了一些額外的說明, 當(dāng)我第一次遇到這個類型時,也是有點恐懼的,后來,用慣了,也就無所謂了。SAFEARRAY單獨用的時候很少,就像我前面說的, 一般都是搭配著VARIANT一起使用,指定vt類型以后,parray成員就是指向SAFEARRAY的指針。SAFEARRAY中元素的類型可以 是VARIANT能封裝的任何類型,包括VARIANT類型本身。 訪問SAFEARRAY 訪問SAFEARRAY的方法大體上有兩種: 使用SafeArrayAccessData方法; 使用SafeArrayGetElement和SafeArrayPutElement方法。 關(guān)于這兩種方法,在上面的例子中都有涉及。 HRESULT 函數(shù)返回值 每個人在做程序設(shè)計的時候,都有他們各自的哲學(xué)思想。拿函數(shù)返回值來說,就有好多種形式。 函數(shù) 返回值 返回值信息 double sin(double) 浮點數(shù)值 計算正玄值 BOOL DeleteFile(LPCTSTR) 布爾值 文件刪除是否成功。如失敗,需要GetLastError()才能取得失敗原因 void * malloc(size_t) 內(nèi)存指針 內(nèi)存申請,如果失敗,返回空指針 NULL LONG RegDeleteKey(HKEY,LPCTSTR) 整數(shù) 刪除注冊表項。0表示成功,非0失敗,同時這個值就反映了失敗的原因 UINT DragQueryFile(HDROP,UINT,LPTSTR,UINT) 整數(shù) 取得拖放文件信息。以不同的參數(shù)調(diào)用,則返回不同的含義: 一會兒表示文件個數(shù),一會兒表示文件名長度,一會兒表示字符長度 ...... ...... ... ...... ...... 如此紛繁復(fù)雜的返回值,如此含義多變的返回值,使得大家在學(xué)習(xí)和使用的過程中,增加了額外的困難。好了,COM 的設(shè)計規(guī)范終于對他們進行了統(tǒng)一。組件API及接口指針中,除了IUnknown::AddRef()和IUnknown::Release()兩個函數(shù)外,其它所有的函數(shù),都以 HRESULT 作為返回值。大家想象一個組件的接口函數(shù)比如叫Add(),完成2個整數(shù)的加法運算,在 C語言 中,我們可以如下定義: view plain copy print ? long Add( long n1, long n2) { return n1+n2; } 還記得剛才我們說的原則嗎? COM 組件是運行在分布式環(huán)境中的 。也就是說,這個函數(shù)可能運行在“地球另一邊”的計算機上,既然運行在那么遙遠的地方,就有可能出現(xiàn)服務(wù)器關(guān)機、網(wǎng)絡(luò)掉線、運行超時、對方不在服務(wù)區(qū)......等異常。于是,這個加法函數(shù),除了需要返回運算結(jié)果以外,還應(yīng)該返回一個值------函數(shù)是否被正常執(zhí)行了。 view plain copy print ? HRESULT Add( long n1, long n2, long *pSum) { 3*pSum=n1+n2; return S_OK; } 如果函數(shù)正常執(zhí)行,則返回 S_OK,同時真正的函數(shù)運行結(jié)果則通過參數(shù)指針返回。如果遇到了異常情況,則COM系統(tǒng)經(jīng)過判斷,會返回相應(yīng)的錯誤值。常見的返回值有: HRESULT 值 含義 S_OK 0x00000000 成功 S_FALSE 0x00000001 函數(shù)成功執(zhí)行完成,但返回時出現(xiàn)錯誤 E_INVALIDARG 0x80070057 參數(shù)有錯誤 E_OUTOFMEMORY 0x8007000E 內(nèi)存申請錯誤 E_UNEXPECTED 0x8000FFFF 未知的異常 E_NOTIMPL 0x80004001 未實現(xiàn)功能 E_FAIL 0x80004005 沒有詳細說明的錯誤。一般需要取得 Rich Error 錯誤信息(注1) E_POINTER 0x80004003 無效的指針 E_HANDLE 0x80070006 無效的句柄 E_ABORT 0x80004004 終止操作 E_ACCESSDENIED 0x80070005 訪問被拒絕 E_NOINTERFACE 0x80004002 不支持接口 圖一、HRESULT 的結(jié)構(gòu) HRESULT 其實是一個雙字節(jié)的值,其最高位(bit)如果是0表示成功,1表示錯誤。具體參見 MSDN 之"Structure of COM Error Codes"說明。我們在程序中如果需要判斷返回值,則可以使用比較運算符號;switch開關(guān)語句;也可以使用VC提供的宏: view plain copy print ? HRESULT hr=調(diào)用組件函數(shù); if (SUCCEEDED(hr)){...} //如果成功 ...... if (FAILED(hr)){...} //如果失敗 ......
個人分類: FreeBasic|4226 次閱讀|0 個評論
分享 Freebasic菜鳥初學(xué)Freebasic基礎(chǔ)教程五:宏參數(shù)的字符串化#和宏參數(shù)的連接##符號
ganlinlao 2017-5-8 18:44
關(guān)于#和## 在C語言的宏中,#的功能是將其后面的宏參數(shù)進行字符串化操作(Stringfication),簡單說就是在對它所引用的宏變量 通過替換后在其左右各加上一個雙引號。比如下面代碼中的宏: #define WARN_IF(EXP) do{ if (EXP) fprintf(stderr, "Warning: " #EXP "/n"); } while(0) 那么實際使用中會出現(xiàn)下面所示的替換過程: WARN_IF (divider == 0); 被替換為 do { if (divider == 0) fprintf(stderr, "Warning" "divider == 0" "/n"); } while(0); 這樣每次divider(除數(shù))為0的時候便會在標(biāo)準(zhǔn)錯誤流上輸出一個提示信息。 而##被稱為連接符(concatenator),用來將兩個Token連接為一個Token。注意這里連接的對象是Token就行,而不一定 是宏的變量。比如你要做一個菜單項命令名和函數(shù)指針組成的結(jié)構(gòu)體的數(shù)組,并且希望在函數(shù)名和菜單項命令名之間有直觀的、名字上的關(guān)系。那么下面的代碼就非常實用: struct command { char * name; void (*function) (void); }; #define COMMAND(NAME) { NAME, NAME ## _command } // 然后你就用一些預(yù)先定義好的命令來方便的初始化一個command結(jié)構(gòu)的數(shù)組了: struct command commands[] = { COMMAND(quit), COMMAND(help), ... } COMMAND宏在這里充當(dāng)一個代碼生成器的作用,這樣可以在一定程度上減少代碼密度,間接地也可以減少不留心所造成的錯誤。我們還可以n個##符號連接 n+1個Token,這個特性也是#符號所不具備的。比如: #define LINK_MULTIPLE(a,b,c,d) a##_##b##_##c##_##d typedef struct _record_type LINK_MULTIPLE(name,company,position,salary); // 這里這個語句將展開為: // typedef struct _record_type name_company_position_salary; 關(guān)于...的使用 ...在C宏中稱為Variadic Macro,也就是變參宏。比如: #define myprintf(templt,...) fprintf(stderr,templt,__VA_ARGS__) // 或者 #define myprintf(templt,args...) fprintf(stderr,templt,args) 第一個宏中由于沒有對變參起名,我們用默認的宏__VA_ARGS__來替代它。第二個宏 中,我們顯式地命名變參為args,那么我們在宏定義中就可以用args來代指變參了。同C語言的stdcall一樣,變參必須作為參數(shù)表的最有一項出 現(xiàn)。當(dāng)上面的宏中我們只能提供第一個參數(shù)templt時,C標(biāo)準(zhǔn)要求我們必須寫成: myprintf(templt,); 的形式。這時的替換過程為: myprintf("Error!/n",); 替換為: fprintf(stderr,"Error!/n",); 這是一個語法錯誤,不能正常編譯。這個問題一般有兩個解決方法。首先,GNU CPP提供的解決方法允許上面的宏調(diào)用寫成: myprintf(templt); 而它將會被通過替換變成: fprintf(stderr,"Error!/n",); 很明顯,這里仍然會產(chǎn)生編譯錯誤(非本例的某些情況下不會產(chǎn)生編譯錯誤)。除了這種方式外,c99和GNU CPP都支持下面的宏定義方式: #define myprintf(templt, ...) fprintf(stderr,templt, ##__VAR_ARGS__) 這時,##這個連接符號充當(dāng)?shù)淖饔镁褪钱?dāng)__VAR_ARGS__為空的時候,消除前面的那個逗號。那么此時的翻譯過程如下: myprintf(templt); 被轉(zhuǎn)化為: fprintf(stderr,templt); 這樣如果templt合法,將不會產(chǎn)生編譯錯誤。 這里列出了一些宏使用中容易出錯的地方,以及合適的使用方式。 錯誤的嵌套-Misnesting 宏的定義不一定要有完整的、配對的括號,但是為了避免出錯并且提高可讀性,最好避免這樣使用。 由操作符優(yōu)先級引起的問題-Operator Precedence Problem 由于宏只是簡單的替換,宏的參數(shù)如果是復(fù)合結(jié)構(gòu),那么通過替換之后可能由于各個參數(shù)之間的操作符優(yōu)先級高于單個參數(shù)內(nèi)部各部分之間相互作用的操作符優(yōu)先級,如果我們不用括號保護各個宏參數(shù),可能會產(chǎn)生預(yù)想不到的情形。比如: #define ceil_div(x, y) (x + y - 1) / y 那么 a = ceil_div( b c, sizeof(int) ); 將被轉(zhuǎn)化為: a = ( b c + sizeof(int) - 1) / sizeof(int); // 由于+/-的優(yōu)先級高于的優(yōu)先級,那么上面式子等同于: a = ( b (c + sizeof(int) - 1)) / sizeof(int); 這顯然不是調(diào)用者的初衷。為了避免這種情況發(fā)生,應(yīng)當(dāng)多寫幾個括號: #define ceil_div(x, y) (((x) + (y) - 1) / (y)) 消除多余的分號-Semicolon Swallowing 通常情況下,為了使函數(shù)模樣的宏在表面上看起來像一個通常的C語言調(diào)用一樣,通常情況下我們在宏的后面加上一個分號,比如下面的帶參宏: MY_MACRO(x); 但是如果是下面的情況: #define MY_MACRO(x) { /* line 1 */ /* line 2 */ /* line 3 */ } //... if (condition()) MY_MACRO(a); else {...} 這樣會由于多出的那個分號產(chǎn)生編譯錯誤。為了避免這種情況出現(xiàn)同時保持MY_MACRO(x);的這種寫法,我們需要把宏定義為這種形式: #define MY_MACRO(x) do { /* line 1 */ /* line 2 */ /* line 3 */ } while(0) 這樣只要保證總是使用分號,就不會有任何問題。 Duplication of Side Effects 這里的Side Effect是指宏在展開的時候?qū)ζ鋮?shù)可能進行多次Evaluation(也就是取值),但是如果這個宏參數(shù)是一個函數(shù),那么就有可能被調(diào)用多次從而達到不一致的結(jié)果,甚至?xí)l(fā)生更嚴(yán)重的錯誤。比如: #define min(X,Y) ((X) (Y) ? (Y) : (X)) //... c = min(a,foo(b)); 這時foo()函數(shù)就被調(diào)用了兩次。為了解決這個潛在的問題,我們應(yīng)當(dāng)這樣寫min(X,Y)這個宏: #define min(X,Y) ({ typeof (X) x_ = (X); typeof (Y) y_ = (Y); (x_ y_) ? x_ : y_; }) ({...})的作用是將內(nèi)部的幾條語句中最后一條的值返回,它也允許在內(nèi)部聲明變量(因為它通過大括號組成了一個局部Scope)。
個人分類: FreeBasic|3527 次閱讀|0 個評論
分享 Freebasic菜鳥初學(xué)Freebasic基礎(chǔ)教程四:了解條件編譯
ganlinlao 2017-5-8 18:25
這種能夠根據(jù)不同情況編譯不同代碼、產(chǎn)生不同目標(biāo)文件的機制,稱為條件編譯。條件編譯是預(yù)處理程序的功能,不是編譯器的功能。 條件編譯有多種形式,下面一一講解。 #if 命令 #if 命令的完整格式為: #if 整型常量表達式1 程序段1 #elseif 整型常量表達式2 程序段2 #elseif 整型常量表達式3 程序段3 #else 程序段4 #endif 它的意思是:如!氨磉_式1”的值為真(非0),就對“程序段1”進行編譯,否則就計算“表達式2”,結(jié)果為真的話就對“程序段2”進行編譯,為假的話就繼續(xù)往下匹配,直到遇到值為真的表達式,或者遇到 #else。這一點和 if else 非常類似。 需要注意的是,#if 命令要求判斷條件為“整型常量表達式”,也就是說,表達式中不能包含變量,而且結(jié)果必須是整數(shù);而 if 后面的表達式?jīng)]有限制,只要符合語法就行。這是 #if 和 if 的一個重要區(qū)別。 #elseif 和 #else 也可以省略,如下所示: #if __FB_WIN32__ print "This is Windows!\n" #else print("Unknown platform!\n" #endif #if __FB_LINUX__ printf("This is Linux!\n"); #endif #ifdef 命令 #ifdef 命令的格式為: #ifdef 宏名 程序段1 #else 程序段2 #endif 它的意思是,如果當(dāng)前的宏已被定義過,則對“程序段1”進行編譯,否則對“程序段2”進行編譯。 也可以省略 #else: #ifdef 宏名 程序段 #endif #ifdef __fb_debug__ print "正在使用 Debug 模式編譯程序..." #else print"正在使用 Release 模式編譯程序..." #endif 當(dāng)以 Debug 模式編譯程序時,宏 _DEBUG 會被定義,預(yù)處器會保留第 5 行代碼,刪除第 7 行代碼。反之會刪除第 5 行,保留第 7 行。 #ifndef 命令 #ifndef 命令的格式為: #ifndef 宏名 程序段1 #else 程序段2 #endif 與 #ifdef 相比,僅僅是將 #ifdef 改為了 #ifndef。它的意思是,如果當(dāng)前的宏未被定義,則對“程序段1”進行編譯,否則對“程序段2”進行編譯,這與 #ifdef 的功能正好相反。 區(qū)別 最后需要注意的是,#if 后面跟的是“整型常量表達式”,而 #ifdef 和 #ifndef 后面跟的只能是一個宏名,不能是其他的。 例如,下面的形式只能用于 #if: #define NUM 10 #if NUM = 10 or NUM = 20 print "NUM: " NUM #else print "NUM Error" #EndIf 運行結(jié)果: NUM: 10 再如,兩個宏都存在時編譯代碼A,否則編譯代碼B: #define NUM1 10 #define NUM2 20 #if Defined(NUM1) And Defined(NUM2) Print "NUM1:" NUM1 Chr(10) "NUM2: " NUM2 #else print "Error" #EndIf sleep 運行結(jié)果: NUM1: 10, NUM2: 20 #ifdef 可以認為是 #if defined 的縮寫。
個人分類: FreeBasic|2753 次閱讀|0 個評論
分享 Freebasic菜鳥初學(xué)Freebasic基礎(chǔ)教程三:帶參數(shù)的宏定義
ganlinlao 2017-5-8 17:43
FB語言允許宏帶有參數(shù)。在宏定義中的參數(shù)稱為形式參數(shù),在宏調(diào)用中的參數(shù)稱為實際參數(shù),這點和函數(shù)有些類似。 '冬瓜湯改編自c語言中文網(wǎng)c語言基礎(chǔ)入門 對帶參數(shù)的宏,在調(diào)用中,不僅要宏展開,而且要用實參去代換形參。 帶參宏定義的一般形式為: #define 宏名(形參列表) 字符串 在字符串中含有各個形參。 帶參宏調(diào)用的一般形式為: 宏名(實參列表); 例如: #define M(y) y*y+3*y '宏定義 '// Code k=M(5); //宏調(diào)用 在宏調(diào)用時,用實參5去代替形參y,經(jīng)預(yù)處理宏展開后的語句為k=5*5+3*5。 【示例】輸出兩個數(shù)中較大的數(shù)。 #define MAX(a,b) iif(ab, a , b) Dim As long x,y,myMax input "請輸入一個數(shù)字: " ,x Input "請輸入另一個數(shù)字:" ,y myMax = MAX(x, y) print myMax sleep 運行結(jié)果: 輸入兩個數(shù)字: 10 20 max=20 程序第2行進行了帶參宏定義,用宏名MAX表示條件表達式iif(ab, a , b),形參a、b均出現(xiàn)在條件表達式中。程序第7行myMax=MAX(x, y)為宏調(diào)用,實參 x、y 將代換形參a、b。宏展開后該語句為: max=iif(xy, x , y) 對帶參宏定義的說明 1) 帶參宏定義中,形參之間可以出現(xiàn)空格,但是宏名和形參列表之間不能有空格出現(xiàn)。例如把: #define MAX(a,b) iif(ab, a , b) 寫為: #define MAX (a,b) iif(ab, a , b) 將被認為是無參宏定義,宏名MAX代表字符串(a,b) iif(ab, a , b)。宏展開時,宏調(diào)用語句: max=MAX(x,y); 將變?yōu)椋?max=(a,b)iif(ab, a , b)(x,y) 這顯然是錯誤的。 2) 在帶參宏定義中,不會為形式參數(shù)分配內(nèi)存,因此不必指明數(shù)據(jù)類型。而在宏調(diào)用中,實參包含了具體的數(shù)據(jù),要用它們?nèi)ゴ鷵Q形參,因此必須指明數(shù)據(jù)類型。 這一點和函數(shù)是不同的:在函數(shù)中,形參和實參是兩個不同的變量,都有自己的作用域,調(diào)用時要把實參的值傳遞給形參;而在帶參數(shù)的宏中,只是符號的替換,不存在值傳遞的問題。 【示例】輸入 n,輸出 (n+1)^2 的值。 #define SQ(y) (y)*(y) Dim As Long a, sq; input "input a number: ",a sq = SQ(a+1); print "sq=" + sq 運行結(jié)果: input a number: 9 sq=100 第2行為宏定義,形參為 y。第7行宏調(diào)用中實參為 a+1,是一個表達式,在宏展開時,用 a+1 代換 y,再用 (y)*(y) 代換 SQ,得到如下語句: sq=(a+1)*(a+1); 這與函數(shù)的調(diào)用是不同的,函數(shù)調(diào)用時要把實參表達式的值求出來再傳遞給形參,而宏展開中對實參表達式不作計算,直接按照原樣替換。 3) 在宏定義中,字符串內(nèi)的形參通常要用括號括起來以避免出錯。例如上面的宏定義中 (y)*(y) 表達式的 y 都用括號括起來,因此結(jié)果是正確的。如果去掉括號,把程序改為以下形式: #define SQ(y) y*y Dim As Long a, sq; input "input a number: ",a sq = SQ(a+1); print "sq=" + sq 運行結(jié)果為: input a number: 9 sq=19 同樣輸入9,但結(jié)果卻是不一樣的。問題在哪里呢?這是由于替換只作符號替換而不作其它處理而造成的。宏替換后將得到以下語句: sq=a+1*a+1; 由于a為9故sq的值為19。這顯然與題意相違,因此參數(shù)兩邊的括號是不能少的。即使在參數(shù)兩邊加括號還是不夠的,請看下面程序: #define SQ(y) (y)*(y) Dim As Long a, sq; input "input a number: ",a sq = 200/SQ(a+1); print "sq=" + sq 與前面的代碼相比,只是把宏調(diào)用語句改為: sq=200/SQ(a+1); 運行程序后,如果仍然輸入 9,那么我們希望的結(jié)果為 2。但實際情況并非如此: input a number: 9 sq=200 為什么會得這樣的結(jié)果呢?分析宏調(diào)用語句,在宏展開之后變?yōu)椋?sq=200/(a+1)*(a+1); a 為 9 時,由于“/”和“*”運算符優(yōu)先級和結(jié)合性相同,所以先計算 200/(9+1),結(jié)果為 20,再計算 20*(9+1),最后得到 200。 為了得到正確答案,應(yīng)該在宏定義中的整個字符串外加括號: #define SQ(y) ((y)*(y)) Dim As Long a, sq; input "input a number: ",a sq = 200/SQ(a+1); print "sq=" + sq 由此可見, 對于帶參宏定義不僅要在參數(shù)兩側(cè)加括號,還應(yīng)該在整個字符串外加括號。 帶參數(shù)的宏和函數(shù)很相似,但有本質(zhì)上的區(qū)別: 宏展開僅僅是字符串的替換,不會對表達式進行計算;宏在編譯之前就被處理掉了,它沒有機會參與編譯,也不會占用內(nèi)存。而函數(shù)是一段可以重復(fù)使用的代碼,會被編譯,會給它分配內(nèi)存,每次調(diào)用函數(shù),就是執(zhí)行這塊內(nèi)存中的代碼。
個人分類: FreeBasic|2699 次閱讀|0 個評論
分享 Freebasic菜鳥初學(xué)Freebasic基礎(chǔ)教程二:宏定義和預(yù)處理命令
ganlinlao 2017-5-8 11:09
'冬瓜湯改編自c語言中文網(wǎng)的c語言基礎(chǔ)入門 宏定義是預(yù)處理命令的一種,它允許用一個標(biāo)識符來表示一個字符串。 先看一個例子: #define N 100 dim sum as long sum=20 +N print Sum 運行結(jié)果: 120 該示例中的語句 sum = 20 + N;,N被100代替了。 #define N 100就是宏定義,N為宏名,100是宏的內(nèi)容。 在編譯預(yù)處理時,對程序中所有出現(xiàn)的“宏名”,都用宏定義中的字符串去代換,這稱為“宏代換”或“宏展開”。 宏定義是由源程序中的宏定義命令#define完成的,宏代換是由預(yù)處理程序完成的。 宏定義的一般形式為: #define 宏名 字符串 #表示這是一條預(yù)處理命令,所有的預(yù)處理命令都以#開頭。define是預(yù)處理命令。宏名是標(biāo)識符的一種,命名規(guī)則和標(biāo)識符相同。字符串可以是常數(shù)、表達式等。 這里所說的字符串是一般意義上的字符序列,不要和FB語言中的字符串等同,它不需要雙引號。 程序中反復(fù)使用的表達式就可以使用宏定義,例如: #define M (n*n+3*n) 它的作用是指定標(biāo)識符M來代替表達式(y*y+3*y)。 在編寫源程序時,所有的(y*y+3*y)都可由M代替,而對源程序編譯時,將先由預(yù)處理程序進行宏代換, 即用(y*y+3*y)表達式去替換所有的宏名M,然后再進行編譯。 將上面的例子補充完整: 上面的程序中首先進行宏定義,定義M來替代表達式(n*n+3*n),在sum=3*M+4*M+5*M中作了宏調(diào)用。在預(yù)處理時經(jīng)宏展開后該語句變?yōu)椋?sum=3*(n*n+3*n)+4*(n*n+3*n)+5*(n*n+3*n); 需要注意的是,在宏定義中表達式(n*n+3*n)兩邊的括號不能少,否則會發(fā)生錯誤。 如當(dāng)作以下定義后: #difine M n*n+3*n在宏展開時將得到下述語句: s=3*n*n+3*n+4*n*n+3*n+5*n*n+3*n;這相當(dāng)于: 3n2+3n+4n2+3n+5n2+3n 這顯然是不正確的。所以進行宏定義時要注意,應(yīng)該保證在宏代換之后不發(fā)生錯誤。 對宏定義的幾點說明 1) 宏定義是用宏名來表示一個字符串,在宏展開時又以該字符串取代宏名,這只是一種簡單的替換。 字符串中可以含任何字符,可以是常數(shù),也可以是表達式,預(yù)處理程序?qū)λ蛔魅魏螜z查, 如有錯誤,只能在編譯已被宏展開后的源程序時發(fā)現(xiàn)。 2) 宏定義不是說明或語句,在行末不必加分號,如加上分號則連分號也一起替換。 3) 宏定義必須寫在函數(shù)之外,其作用域為宏定義命令起到源程序結(jié)束。如要終止其作用域可使用#undef命令。例如: #define PI 3.14159 Sub main () ' Code return 0 ; end Sub #undef PI Function func () 'Code end Function '========================= 表示PI只在main函數(shù)中有效,在func中無效。 4) 宏名在源程序中若用引號括起來,則預(yù)處理程序不對其作宏代換,例如: #define OK 100 print "OK " 運行結(jié)果: OK 該例中定義宏名OK表示100,但在 print 語句中 OK 被引號括起來,因此不作宏代換,而作為字符串處理。 5) 宏定義允許嵌套,在宏定義的字符串中可以使用已經(jīng)定義的宏名,在宏展開時由預(yù)處理程序?qū)訉哟鷵Q。例如: #define PI 3.1415926 #define S PI*y*y /* PI是已定義的宏名*/ 對語句: print S在宏代換后變?yōu)椋? print 3.1415926*y*y 6) 習(xí)慣上宏名用大寫字母表示,以便于與變量區(qū)別。但也允許用小寫字母。 7) 可用宏定義表示數(shù)據(jù)類型,使書寫方便。例如: #define UINT ULong 在程序中可用UINT作變量說明: dim as uint a, b 應(yīng)注意用宏定義表示數(shù)據(jù)類型和用type…… As定義數(shù)據(jù)說明符的區(qū)別。 宏定義只是簡單的字符串代換,是在預(yù)處理完成的,而type… As是在編譯時處理的,它不是作簡單的代換,而是對類型說明符重新命名。被命名的標(biāo)識符具有類型定義說明的功能。 宏定義雖然也可表示數(shù)據(jù)類型, 但畢竟是作字符代換。在使用時要分外小心,以避出錯。
個人分類: FreeBasic|2774 次閱讀|0 個評論
分享 Freebasic菜鳥初學(xué)Freebasic基礎(chǔ)教程一:一分鐘理解指針
ganlinlao 2017-5-8 10:04
Freebasic菜鳥初學(xué)Freebasic基礎(chǔ)教程一:一分鐘理解指針
Freebsic是一門沒有任何特點的開源語言,非常平庸。它是披著VB的語法羊皮,長著一顆c語言的心,懷著c++的情懷,卻生在一個托管語言橫行的世界。所以本系列文章,謹此獻給極其少數(shù)幾個喜歡Freebasic的人。 freebasic的語法和vb是極其相似的,所以如果你有vb6或vba的基礎(chǔ)的話,那么你用Freebasic寫代碼幾乎沒有任何障礙,非常熟悉,如果你有點c語言基礎(chǔ)的話,你馬上就可以使用Freebasic,F(xiàn)reebasic和c是高度兼容的,而且可以使用gcc或LLvm編譯。本系列適用于有點VB基礎(chǔ)的人看,而且我也只是把c語言的入門教程作一個極其簡單的改編而已。 本部分內(nèi)容改編自c語言中文網(wǎng)中的c語言入門,這個入門教程寫得很不錯,你也可以隨意找一本c語言入門,只看vb沒有的那部分章節(jié)。 '冬瓜湯改編自c語言中文網(wǎng)的c語言入門 一、1分鐘徹底理解指針的概念: 計算機中所有的數(shù)據(jù)都必須放在內(nèi)存中,不同類型的數(shù)據(jù)占用的字節(jié)數(shù)不一樣,例如 long 占用4個字節(jié),boolean 占用1個字節(jié)。為了正確地訪問這些數(shù)據(jù),必須為每個字節(jié)都編上號碼,就像門牌號、身份證號一樣,每個字節(jié)的編號是唯一的,根據(jù)編號可以準(zhǔn)確地找到某個字節(jié)。 下圖是 4G 內(nèi)存中每個字節(jié)的編號(以十六進制表示): 我們將內(nèi)存中字節(jié)的編號稱為 地址(Address) 或 指針(Pointer) 。地址從 0 開始依次增加,對于 32 位環(huán)境,程序能夠使用的內(nèi)存為 4GB,最小的地址為 0,最大的地址為 0XFFFFFFFF。 下面的代碼演示了如何輸出一個地址: dim as long a =100 dim as String myStr ="這是一個FB入門教程" print "a的地址:" varptr(a) print "myStr的地址:" strptr(mystr) sleep 運行結(jié)果: a的地址:1310384 mystr的地址:6164384 FB語言用變量來存儲數(shù)據(jù),用函數(shù)來定義一段可以重復(fù)使用的代碼,它們最終都要放到內(nèi)存中才能供 CPU 使用。 數(shù)據(jù)和代碼都以二進制的形式存儲在內(nèi)存中,計算機無法從格式上區(qū)分某塊內(nèi)存到底存儲的是數(shù)據(jù)還是代碼。當(dāng)程序被加載到內(nèi)存后,操作系統(tǒng)會給不同的內(nèi)存塊指定不同的權(quán)限,擁有讀取和執(zhí)行權(quán)限的內(nèi)存塊就是代碼,而擁有讀取和寫入權(quán)限(也可能只有讀取權(quán)限)的內(nèi)存塊就是數(shù)據(jù)。 CPU 只能通過地址來取得內(nèi)存中的代碼和數(shù)據(jù),程序在執(zhí)行過程中會告知 CPU 要執(zhí)行的代碼以及要讀寫的數(shù)據(jù)的地址。如果程序不小心出錯,或者開發(fā)者有意為之,在 CPU 要寫入數(shù)據(jù)時給它一個代碼區(qū)域的地址,就會發(fā)生內(nèi)存訪問錯誤。這種內(nèi)存訪問錯誤會被硬件和操作系統(tǒng)攔截,強制程序崩潰,程序員沒有挽救的機會。 CPU 訪問內(nèi)存時需要的是地址,而不是變量名和函數(shù)名!變量名和函數(shù)名只是地址的一種助記符,當(dāng)源文件被編譯和鏈接成可執(zhí)行程序后,它們都會被替換成地址。編譯和鏈接過程的一項重要任務(wù)就是找到這些名稱所對應(yīng)的地址。 假設(shè)變量 a、b、c 在內(nèi)存中的地址分別是 0X1000、0X2000、0X3000,那么加法運算c = a + b;將會被轉(zhuǎn)換成類似下面的形式: 0X3000 = (0X1000) + (0X2000); ( )表示取值操作,整個表達式的意思是,取出地址 0X1000 和 0X2000 上的值,將它們相加,把相加的結(jié)果賦值給地址為 0X3000 的內(nèi)存 變量名和函數(shù)名為我們提供了方便,讓我們在編寫代碼的過程中可以使用易于閱讀和理解的英文字符串,不用直接面對二進制地址,那場景簡直讓人崩潰。 需要注意的是,雖然變量名、函數(shù)名、字符串名和數(shù)組名在本質(zhì)上是一樣的,它們都是地址的助記符,但在編寫代碼的過程中,我們認為變量名表示的是數(shù)據(jù)本身,而函數(shù)名、字符串名和數(shù)組名表示的是代碼塊或數(shù)據(jù)塊的首地址。
個人分類: FreeBasic|5749 次閱讀|0 個評論
分享 FreeBasic的面向?qū)ο笕腴T三——冬瓜湯整理
熱度 2 ganlinlao 2014-10-9 10:07
12、基類和子類 一個基類可以是另一個基類的子類,這樣便形成了復(fù)雜的繼承結(jié)構(gòu)。出現(xiàn)了類的層次。 一個基類派出一個子類 A ,該子類又做了另一個子類 B的基類。則原來的基類為子類 B 的間接基類。 子類是基類的特殊化 子類是基類定義的延續(xù) 基類是子類的公有特性 子類將其自身與基類區(qū)別開來的方法是添加數(shù)據(jù)成員和成員函數(shù) 如何定義子類呢? Type 學(xué)生 …… End type Type 大學(xué)生 extends 學(xué)生 …… End type 注意: 關(guān)鍵詞 extends 是復(fù)數(shù)形式 13、Freebasic繼承的方式 目前到 freebasic1.0 為止, FB的子類 只能以 public 方式繼承自基類。(也許是我不知道如何使用protected方式繼承) Public 方式的特點: 可以在子類的成員函數(shù)中訪問基類的非私有成員數(shù)據(jù) 可通過子類的對象直接訪問基類的公有成員 14、基類和子類的重名成員 子類定義了與基數(shù)同名的成員,在子類中訪問同名成員時,自動隱藏基類的同名成員 在子類中使用基類的同名成員,可以顯式使用基類名 . 成員或base.成員 15、基類和子類的構(gòu)造函數(shù) 一個子類對象也屬于其基類,因此當(dāng)程序創(chuàng)建一個子類對象時,系統(tǒng)首先自動創(chuàng)建一個基類的對象。 在調(diào)用子類的構(gòu)造函數(shù)構(gòu)建子類對象時,系統(tǒng)首先調(diào)用基類的構(gòu)造函數(shù)構(gòu)建基類對象,當(dāng)子類對象的生存期結(jié)束時,首先調(diào)用子類的析構(gòu)函數(shù),然后調(diào)用基類的析構(gòu)函數(shù) 基類構(gòu)造函數(shù)的調(diào)用方式 : 隱式調(diào)用和顯式調(diào)用兩種方式 : (1) 隱式方式是指在子類的構(gòu)造函數(shù)中不指定對對應(yīng)的基類的構(gòu)造函數(shù),調(diào)用的是基類的默認構(gòu)造函 數(shù)即含有缺省參數(shù)值和不帶有參數(shù)的構(gòu)造函數(shù)) (2) 顯式方式是指在子類的構(gòu)造函數(shù)中指定要調(diào)用的基類構(gòu)造函數(shù)。并將子類構(gòu)造函數(shù)的部分參數(shù)值傳遞給基類構(gòu)造函數(shù)(注:除非基類有默認的構(gòu)造函數(shù),否則必 須采用顯式調(diào)用方式) 16、多態(tài)性和虛函數(shù) 什么是多態(tài)性? 多態(tài)性是面向?qū)ο蟪绦蛟O(shè)計的一個重要特征,它主要表現(xiàn)在函數(shù)調(diào)用時實現(xiàn)“一種接口,多種方法”。 兩種多態(tài)性: 編譯時多態(tài)性和運行時多態(tài)性。 編譯時多態(tài)性:在函數(shù)名或運算符相同的情況下,編譯器在編譯階段就能能夠根據(jù)函數(shù)參數(shù)類型的 不同來確定要調(diào)用的函數(shù) — 通過重載實現(xiàn)。 運行時多態(tài)性:在函數(shù)名、函數(shù)參數(shù)和返回類型都楨同的情況下,只能在程序 運行時 才能確定要調(diào)用的函數(shù)——通過虛函數(shù)實現(xiàn)。 17、虛函數(shù) virtual 虛函數(shù)是在基類中冠以 virtual 的成員函數(shù)。它提供了一種接口 虛函數(shù)可以在一個或多個子類中被重定義 實現(xiàn)運行時多態(tài)的關(guān)鍵首先是要說明虛函數(shù) 必須用基類指針調(diào)用子類的不同實現(xiàn)版本。 (1)、虛函數(shù)的定義 定義:在某基類中聲明為 virtual 并在一個或多個子類中被重新定義的成員函數(shù)。 語法: virtual Function 函數(shù)名(參數(shù)表) End function    用途: 實現(xiàn)多態(tài)性,通過指向子類的基類指針,訪問子類中同名覆蓋成員函數(shù)   虛函數(shù)必須是基類的非靜態(tài)成員函數(shù),其訪問權(quán)限可以是 protected 或 public 。 定義為 virtual 的函數(shù)是基類期待子類重新定義的,基類希望子類繼承的函數(shù)不能定義為虛函數(shù)。 (2)、虛函數(shù)的作用 虛函數(shù)的作用是實現(xiàn)動態(tài)聯(lián)編,也就是在程序的運行階段動態(tài)地選擇合適的成員函數(shù),在定義了虛函 數(shù)后,可以在基類的子類中對虛函數(shù)重新定義,在子類中重新定義的函數(shù)應(yīng)與虛函數(shù)具有相同的形參 個數(shù)和形參類型。以實現(xiàn)統(tǒng)一的接口,不同定義過程。如果在子類中沒有對虛函數(shù)重新定義,則它 繼承其基類的虛函數(shù)!  當(dāng)程序發(fā)現(xiàn)虛函數(shù)名前的關(guān)鍵字 virtual 后,會自動將其作為動態(tài)聯(lián)編處理,即在程序運行時動態(tài)地選擇 合適的成員函數(shù)。虛函數(shù)是 FreeBasic 多態(tài)的一種表現(xiàn)。 使用虛函數(shù),我們可以靈活的進行動態(tài)綁定,當(dāng)然是以一定的開銷為代價。如果父類的函數(shù)(方法) 根本沒有必要或者無法實現(xiàn),完全要依賴子類去實現(xiàn)的話,可以把此函數(shù)(方法)設(shè)為 virtual 函數(shù)名 =0 我們把這樣的函數(shù)(方法)稱為純虛函數(shù),如果一個類包含了純虛函數(shù),稱此類為抽象類。 我們只需在把基類的成員函數(shù)設(shè)為 virtual ,其子類的相應(yīng)的函數(shù)也會自動變?yōu)樘摵瘮?shù)。 (3)虛函數(shù)的動態(tài)綁定過程 表面點來說,虛函數(shù)是根據(jù)調(diào)用它的指針或引用所指向或綁定的對象的類型來調(diào)用綁定或指向的類型 所定義的虛函數(shù)版本。 由于類中有虛函數(shù)存在,所以編譯器就會為這個類插入一段你不知道的數(shù)據(jù),并為它創(chuàng)建一個表。那段數(shù)據(jù)叫做 vptr 指針,指向那個表。那個表叫做 vtbl ,每個類都有自己的 vtbl , vtbl 的作用就是保存自定義為 virtual 的函數(shù)是基類期待子類重新定義的,基類希望子類繼承的函數(shù)不能定義為虛函數(shù)。基類中虛函數(shù)的地址,我們可以把 vtbl 形象地看成一個數(shù)組,這個數(shù)組的每個元素存放的就是虛函數(shù)的地址。 調(diào)用虛函數(shù)時,首先是取出 vptr 的值,這個值就是 vtbl 的地址,再根據(jù)這個值來到 vtbl 這里,取出 vtbl 中相應(yīng)的 slot 里的值,這個值就是所在調(diào)用的虛函數(shù)的地址了,最后調(diào)用這個函數(shù)。現(xiàn)在我們可以看出來了,只要 vptr 不同,指向的 vtbl 就不同,而不同的 vtbl 里裝著對應(yīng)類的虛函數(shù)地址,所以這樣虛函數(shù)就可以完成它的任務(wù)。 (4)純虛函數(shù) 在基類中不能對虛函數(shù)給出有意義的實現(xiàn),而把它聲明為純虛函數(shù),它的實現(xiàn)留給該基類的子類去做。這就是純虛函數(shù)的作用。 純虛函數(shù)可以讓類先具有一個操作名稱,而沒有操作內(nèi)容,讓子類在繼承時再去具體地給出定義。凡是含有純虛函數(shù)的類叫做抽象類。這種類不能聲明對象,只是作為基類為子類服務(wù)。除非在子類中完全實現(xiàn)基類中所有的的純虛函數(shù),否則,子類也變成了抽象類,不能實例化對象。在函數(shù)形參后面寫上= 0 以指定純虛函數(shù)。 17、函數(shù)重載 函數(shù)重載:是指一組功能類似但函數(shù)參數(shù)類型(或個數(shù))不同的函數(shù)可以共用一個函數(shù)名。 當(dāng) FB 編譯器遇到重載函數(shù)的調(diào)用語句時,它能夠根據(jù)不同的參數(shù)類型或不同的參數(shù)個數(shù)選擇一個合適的函數(shù)。 不能利用函數(shù)返回類型的不同進行函數(shù)重載。 因為在沒有確定調(diào)用的是哪個函數(shù)之前,不知道函數(shù)的返回類型。 同樣,不能利用引用進行函數(shù)重載。 一般函數(shù)的重載使 FB 程序具有更好的可擴充性。此外。類的成員函數(shù)也可以重載,特別是構(gòu)造函數(shù)的重載給 FB 程序設(shè)計帶來很大的靈活性。 如何區(qū)別重載、重寫(覆蓋)和隱藏 ? (1). 重載:重載從 overload 翻譯過來,是 指同一可訪問區(qū)內(nèi)被聲明的幾個具有不同參數(shù)列(參數(shù)的類型,個數(shù),順序不同)的同名函數(shù),根據(jù)參數(shù)列表確定調(diào)用哪個函數(shù),重載不關(guān)心函數(shù)返回類型。 示例代碼如下: Type A public: sub test( I as integer); sub test( I as double); sub test( I as integer, j as double); sub test(I as sing, j as long); function test(I as integer) as long; ‘ 錯誤,非重載 end type 前四個互為重載函數(shù),最后一個和第一個不是重載函數(shù)。 (2). 隱藏:隱藏是 指子類的函數(shù)屏蔽了與其同名的基類函數(shù)。注意只要同名函數(shù),不管參數(shù)列表是否相同,基類函數(shù)都會被隱藏。 (3). 重寫:重寫翻譯自 override ,也翻譯成覆蓋(更好一點),是 指子類中存在重新定義的函數(shù)。其函數(shù)名,參數(shù)列表,返回值類型,所有都必須同基類中被重寫的函數(shù)一致。只有函數(shù)體不同,子類調(diào)用時會調(diào)用子類的重寫函數(shù),不會調(diào)用被重寫函數(shù)。 重寫的基類中被重寫的函數(shù)必須有 virtual 修飾 。 Type A public: virtual Function fun3( I as long) as long{ return i+1 end function end type type B extends A ‘B 從 A 繼承 public: ‘ 重寫 virtual Function fun3( I as long) as long return i*3 end function end type 重載和重寫的區(qū)別: ( 1 )范圍區(qū)別: 重寫和被重寫的函數(shù)在不同的類中,重載和被重載的函數(shù)在同一類中。 ( 2 )參數(shù)區(qū)別: 重寫與被重寫的函數(shù)參數(shù)列表一定相同,重載和被重載的函數(shù)參數(shù)列表一定不同。 ( 3 ) virtual 的區(qū)別: 重寫的基類必須要有 virtual 修飾,重載函數(shù)和被重載函數(shù)可以被 virtual 修飾,也可以沒有。 隱藏和重寫,重載的區(qū)別: ( 1 )與重載范圍不同: 隱藏函數(shù)和被隱藏函數(shù)在不同類中。 ( 2 )參數(shù)的區(qū)別: 隱藏函數(shù)和被隱藏函數(shù)參數(shù)列表可以相同,也可以不同,但函數(shù)名一定同;當(dāng)參數(shù)不同時,無論基類中的函數(shù)是否被 virtual 修飾,基類函數(shù)都是被隱藏,而不是被重寫。
個人分類: FreeBasic|3264 次閱讀|2 個評論
分享 FreeBasic中的指針基礎(chǔ)入門二----指針與數(shù)組的關(guān)系——冬瓜湯整理
ganlinlao 2014-9-30 22:18
FreeBasic中的指針基礎(chǔ)入門二----指針與數(shù)組的關(guān)系——冬瓜湯整理
3、數(shù)組和指針的關(guān)系 數(shù)組的數(shù)組名其實可以看作一個指針。 例九: Dim MyArray(9) as long={0,1,2,3,4,5,6,7,8,9} Dim value as long Value = MyArray(0) /’ 也可以寫成: value=*MyArray ‘/ Value = Myarray(3) ‘ 也可以寫成: value = *(myarray+3) Value=MyArray(4) ‘ 也可以寫成: value=*(MyArray +4) 一般而言 數(shù)組名 Myarray 代表數(shù)組本身,類型是 long ,但如果把 array 看做指針的話,它指向數(shù)組的第 0 個單元,類型是 long ptr , 所指向的類型是數(shù)組單元的類型即 long 。 因此 *Myarray 等于 0 就一點也不 奇怪了。 同理, Myarray+3 是一個指向數(shù)組第 3 個單元的指針,所以 *(array+3) 等于 3 。 其它依此類推。 用下圖來顯示可能更直白一點: 注:在 FreeBasic 中,數(shù)組下標(biāo)的表示法是 A(i) ,指針數(shù)組是用 P 表示,這兩者有區(qū)別。 4、指針的運算 4.1指針的賦值運算 4.2、指針的算術(shù)運算 指針可以加上或減去一個整數(shù)。 指針的這種運算的意義和通常的數(shù)值的加減運算的意義是不一樣的,以單元為單位。 例二: Dim a(20) as string Dim P as string ptr P=@a(0) P +=1 說明:在 p +=1 中,指針變量 P 被加了 1 。編譯器是這樣處理的: 它把指針 P 的值加上了 sizeof(string) 注:兩個指針不能進行加法運算,這是非法操作。因為進行加法后, 得到的結(jié)果指向一個不知道指向的地方,而且毫無意義。 在同一個數(shù)組中,兩個指針可以進行減法操作,但必須類型相同。 4.3、指針的關(guān)系運算 5、指針與二維數(shù)組
個人分類: FreeBasic|2526 次閱讀|0 個評論
分享 FreeBasic中的指針基礎(chǔ)入門一----理解指針變量——冬瓜湯整理
ganlinlao 2014-9-30 17:27
FreeBasic中的指針基礎(chǔ)入門一----理解指針變量——冬瓜湯整理
前言 對于使用VB的人,指針概念基本上是一片空白。而指針是C語言最大的特點。在FreeBasic中適當(dāng)?shù)赜煤弥羔,能帶來不少的便利和靈活性。對于指針是適當(dāng)使用而不是濫用。 因此理解指針概念,就變得相當(dāng)有意義了。 1、細說指針 指針是一個特殊的變量,它里面存儲的數(shù)值被解釋成為內(nèi)存里的一個地址。 要搞清一個指針需要搞清指針的四方面的內(nèi)容: 指針的類型、指針?biāo)赶虻念愋、指針的值(或者叫指針(biāo)赶虻膬?nèi)存區(qū))、指針本身所占據(jù)的內(nèi)存區(qū)。 讓我們分別說明: 先聲明幾個指針放著做例子: 例一: (1) 、 dim P as integer ptr (2) 、 dim P as string ptr (3) 、 dim P as integer ptr ptr (4) 、 dim P() as integer ptr 說明: 在 Freebasic 中聲明指針是用 ptr (或 pointer )這個關(guān)鍵字 Dim P as integer ptr ‘ 指針的類型是 integer Dim P as string ptr ‘ 指針的類型是 string 接下來看指針?biāo)赶虻念愋? Dim P as integer ptr ‘ 指針?biāo)赶虻念愋褪? integer Dim p as string ptr ‘ 指針?biāo)赶虻念愋褪? string 注:( 1 )指針的類型(即指針本身的類型)和指針?biāo)赶虻念愋褪莾蓚概念 ( 2 )指針的類型與指針?biāo)赶虻念愋途哂邢嗤念愋? 當(dāng)你對 FB 越來越熟悉時,你會發(fā)現(xiàn),把與指針攪和在一起的 " 類型 " 這個概念分成 " 指針的類型 " 和 " 指針?biāo)赶虻念愋? " 兩個概念,是精通指針的關(guān)鍵點之一。 指針的值 ---- 或者叫指針?biāo)赶虻膬?nèi)存區(qū)(地址)。指針的值是指針本身存儲的數(shù)值,這個值將被編譯器當(dāng)作一個地址,而不是一個一般的數(shù)值。 在 32 位程序里,所有類型的指針的值都是一個 32 位整數(shù),因為 32 位程序里內(nèi)存地址全都是 32 位長。 指針?biāo)赶虻膬?nèi)存區(qū)就是從指針的值所代表的那個內(nèi)存地址開始,長度為 sizeof( 指針?biāo)赶虻念愋? ) 的一片內(nèi)存區(qū)。 以后,我們說一個指針的值是 XX ,就是相當(dāng)于說該指針指向了以 XX 為首地址的一片內(nèi)存域; 我們說一個指針指向了某地塊內(nèi)存區(qū)域,就相當(dāng)于說該指的值是這塊內(nèi)存區(qū)域的首地址。 注:指針?biāo)赶虻膬?nèi)存區(qū)和指針?biāo)赶虻念愋褪莾蓚完全不同的概念。 在例 一中,指針?biāo)赶虻念愋鸵呀?jīng)有了,但由于指針還未初始化,所以它所指向 的內(nèi)存區(qū)是不存在的,或者說是無意義的。 以后,每遇到一個指針,都應(yīng)該問問: 這個指針的類型是什么?指針指 的類型是什么? 該指針指向了哪里?(重點注意) 4 指針本身所占據(jù)的內(nèi)存區(qū) 指針本身占了多大的內(nèi)存? 你只要用函數(shù) sizeof( 指針的類型 ) 測一下 就知道了 。 在 32 位平臺里,指針本身占據(jù)了 4 個字節(jié)的長度。 指針本身占據(jù)的內(nèi)存這個概念在判斷一個指針表達式(后面會解釋)是否是左值時很有用。 下面用圖來展示可能會更清晰: 指針與指針變量的理解: 2 、運算符 @ 和 * 在FreeBasic中 @ 是取地址運算符。 * 是間接運算符(取值運算符)
個人分類: FreeBasic|3148 次閱讀|0 個評論
分享 Freebasic基礎(chǔ)入門1——冬瓜湯整理
熱度 1 ganlinlao 2014-9-25 21:10
Freebasic能用來做什么? 仁都見仁,智者見智。以下是我個人膚淺的理解 1、Freebasic比vba更適合跟硬件打交道。 2、Freebasic的dll可以直接被python和aauto等動態(tài)語言調(diào)用。需要性能的地方用Freebasic,可以顯著提高 性能。當(dāng)然這只是針對不想學(xué)c/c++的人而言。 3、Freebasic可以編譯成原生的64位。如果使用office64位,那么可以用freebasic編寫64位的dll供vba調(diào)用。 注: Freebasic不易用。個人喜好,僅供參考,急于求成者,慎入 一、Freebasic的數(shù)據(jù)類型: 類型 范圍大小 冬瓜湯備注說明 指針類型 指針類型 Ptr,Pointer 數(shù)據(jù)指針 Integer 隨系統(tǒng) 32 位或 64 位變化而變化。 32 位中轉(zhuǎn)變成 long 大小 ,64 位中轉(zhuǎn)成 longint 大小。 相當(dāng)于 VBA 中的 longPtr UINTEGER 整型 字節(jié)型 BYTE -127 至 288 整型 SHORT -32768 至 32767 相當(dāng)于 VBA 中的 integer 長整型 LONG 或 integer -2147483648 至 2147483647 相當(dāng)于 VBA 中的 long 在 32 位的 FB 中 integer 等價 long 64 位長整型 LONGINT -9 223 372 036 854 775 808 至 9 223 372 036 854 775 807 相當(dāng)于 VBA 中的 LongLong 無符整型 字節(jié)型 UBYTE 0 至 255 相當(dāng)于 VBA 中的 Byte 無符整型 USHORT 0 至 65535 無符長整型 ULONG 0 至 4294967295 無符 64 位 ULONGINT 0 至 9 223 372 036 854 775 807 單精度 SINGLE 雙精度 DOUBLE 字符串 String 0 至 2147483647 個字節(jié) 定長字符串 String *N C 字符串 Zstring 同上 兼容 c 寬字符串 Wstring Wstring 主要用于 unicode 兼容 c++ 對象 Object 二、Freebasic操作符: 字符串操作符 + 拼接多個字符串,如果其中一個變量不是 string ,將返回錯誤 強制拼接多個字符串。如果其中一個變量不是 string ,將自動轉(zhuǎn)成 string 數(shù)學(xué)運算符 + - * \ / ^ mod - 取負 SHL 將一個數(shù)值表達式的位左移 SHR 將一個數(shù)值表達式的位右移 比較運算符 = = = is 注意 :FB 沒有 like 這個關(guān)鍵字 索引符 () 用于數(shù)組索引 用于指針數(shù)組索引 邏輯及按位運算符 And Or Not Xor Eqv Imp Andalso orelse 指針操作符 @ 獲取地址 * 取值 成員操作符 . 訪問自定義類型或類的成員 - 訪問成員的指針 賦值操作符 = 賦值 = Str2 =str1 相當(dāng)于 str2=str2str1 += -= *= /= \= ^= Mod= And= Or= Xor= Eqv= Lmp= Shl= Shr= Let 賦值語句,基本不用 Let() 同上
個人分類: FreeBasic|10487 次閱讀|1 個評論

QQ|站長郵箱|小黑屋|手機版|Office中國/Access中國 ( 粵ICP備10043721號-1 )  

GMT+8, 2025-7-13 07:27 , Processed in 0.142129 second(s), 24 queries .

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

返回頂部