雖然之前看過《lua程式設計》(第二版)這本書,但對c與lua互動的部分,一直不是很理解。最近想系統學習和深入理解c與lua的互動(實質是想通過這個,進一步閱讀lua原始碼,:)),因此又看了一下這本書的第4部分,下面是在學習c中呼叫lua的全域性變數、table和函式的筆記以及自己的理解,其中學習過程中的寫的測試**可以從我的github
0、lua與c有兩種互動形式。在第一種形式中,c語言擁有控制權,lua是乙個庫,這種形式中的c**稱為「應用程式**」;在第二種形式中,lua擁有控制權,這種形式中的c**稱為「庫**」。lua的直譯器程式(lua.c)就是「應用程式**」的乙個例項;而lua標準庫(lstrlib.c,lmathlib.c等)則是「庫**」的例項。
應用程式**和庫**(注意他們都是c**,只是功能或者說地位不同)都使用通用的api來與lua**通訊,這些api稱為c api。
1、lua原始碼標頭檔案lua.h中,定義了向c應用程式提供的基礎函式,包括建立lua環境,呼叫lua函式(如lua_pcall)、讀寫lua環境中的全域性變數,以及註冊供lua呼叫的新函式等。lua.h中宣告或定義的函式名都以lua_作為字首。
2、標頭檔案lauxlib.h定義了輔助庫(auxiliary library, auxlib)提供的函式。在該檔案中所定義的函式名都以lual_作為字首。該輔助庫所有函式的實現,都只是用到lua.h中宣告的函式,也就是說,該輔助庫中所有的函式實現不會直接訪問lua的內部,該庫相對於是乙個較高的抽象,用於側重於解決具體任務。
3、lua庫中沒有定義任何全域性變數。它將所有的狀態都儲存在動態結構lua_state中,所有的c api都要求傳入乙個指向該結構的指標。
4、在lua與c之間交換資料時,主要有兩個問題,乙個是動態型別和靜態型別之間的區別,其次是自動記憶體管理和手動記憶體管理之間的區別。為了解決兩個問題,lua與c之間交換資料時利用了乙個抽象的棧。
5、lua中的字串不是以零結尾的,他們可以包含任意二進位制資料。因此,它們必須同時儲存乙個顯示的長度。將字串壓入棧中的基本函式是lua_pushlstring,它要求傳入乙個顯示的長度引數。對於零結尾的字串,可以使用函式lua_pushstring,這個函式通過strlen來計算字串的長度。lua不會持有指向外部(指lua虛擬機器外的)字串的指標。對於所有lua持有的字串,它都會生成乙個內部副本,或者復用現有的內容。因此,即使在這些函式立即返回後立刻釋放或修改這些字串,也不會出現問題。
6、介面中以lua_push*開頭的函式,一般用來向棧中壓入函式,通常lua**呼叫c函式時,呼叫的函式通常就用這些介面,把結果壓入棧中,返回給lua(當然這些c函式也要求返回乙個值,告訴lua一共返回(壓入)了多少個值)。值得注意的是,向棧中壓入乙個元素時,應該確保棧中具有足夠的空間,可以呼叫lua_checkstack來檢測是否有足夠的空間。
7、介面中以lua_to*開頭的函式,一般用於棧中獲取乙個值。通常在c函式中,可以用這些介面獲取從lua中傳遞給c函式的引數。如果指定的元素不具有正確的型別,呼叫這些函式也不會出問題的。在這種情況下,lua_toboolean、lua_tonumber、lua_tointeger和lua_objlen會返回0,而其他函式會返回null。對於返回null的函式,可以直接通過返回值,即可以知道呼叫是否正確;對於返回0的函式,通常先需要使用lua_is*函式,看判斷呼叫是否正確。
8、介面中以lua_get*開頭的函式,呼叫後,一般會向棧頂中壓入乙個元素。比如void lua_gettable(lua_state *l,int index)會向棧頂壓入t[k],這裡的t是棧中索引為index的值,k是棧頂的值。
9、介面中以lual_check*開頭的函式,如果發生錯誤,則總是丟擲乙個錯誤。若正確,則會返回相應型別的值,該介面通常用來檢測lua傳入的引數是否正確。
10、當lua呼叫的乙個c函式返回時,lua就會清空它的棧。也就是說在lua**中呼叫c函式時,當這個c函式返回後,lua虛擬機器就會把其相應的交換資料的棧清空。也說明了,對被呼叫的c函式,從棧中獲取的值,但c函式返回後,就不能再使用了(特別是針對介面lua_tolstring)。
11、幾乎所有的api函式都會丟擲錯誤(即呼叫longjmp),而不是返回錯誤。當編寫庫**時(被lua呼叫的c函式),使用longjmp幾乎和使用異常處理機制一樣方便,lua會捕獲所有可能的錯誤。而當編寫應用程式**時(呼叫lua的c**),必須提供一種捕獲錯誤的方式。在大多數應用程式中,通常都通過呼叫lua_pcall來執行lua**,這樣即使發生錯誤了,應用程式(比如遊戲主程序)也不會結束。如果要保護那些與lua互動的c**,可以使用lua_cpcall。這個函式類似於lua_pcall,但它接受乙個c函式作為引數,然後呼叫這個c函式。
12、在呼叫lua_pcall時,第三個引數是期望的結果數量。就像lua的賦值一樣,lua_pcall會根據要求的數量來調整實際結果的數量,即壓入nil或丟棄多餘的結果。在壓入結果前,lua_pcall會先刪除棧中的函式及其引數。如果乙個函式會返回多個結果,那麼第乙個結果最先壓入。
13、可以使用lual_checktype函式確保給定引數具有特定的型別,否則它會引發乙個錯誤。
學習筆記 C 與lua互相呼叫
1.輸出lua指令碼內容 void start 2.自定義loader void start private byte myloader ref string filepath 3.載入變數 double a luaenv.global.get a 獲取到lua裡面的全域性變數 a print a ...
Lua 學習筆記(二)
這一章我們介紹一下lua中函式的宣告,其實函式這東西我們每個人都接觸過,就像我們初中高中學的一次函式 二次函式是一樣的。舉個簡單的例子吧,目前歐元匯率和人民幣匯率的比例是1歐元換7.2人民幣,那我們手裡有100歐元能換多少人民幣呢?如果是1000歐元呢?遇到這種問題的時候,我們就需要找到乙個規律,然...
Lua中呼叫C函式
lua利用乙個虛擬的堆疊來給c傳遞值或從c獲取值。每當lua呼叫c函式,都會獲得乙個新的堆疊,該堆疊初始包含所有的呼叫c函式所需要的引數值 lua傳給c函式的呼叫實參 並且c函式執行完畢後,會把返回值壓入這個棧 lua從中拿到c函式呼叫結果 1 typedef struct lua state lu...