国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

第二十四課 C API概述

2019-11-11 02:05:11
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友
Lua是一種嵌入式語(yǔ)言,即Lua不是一個(gè)單獨(dú)運(yùn)行的程序,而是一個(gè)可以鏈接到其他程序的庫(kù)。通過(guò)鏈接就可以將Lua的功能合并入這些程序。如果Lua不是一個(gè)獨(dú)立運(yùn)行的程序,那么之前我們使用的Lua程序是怎么來(lái)的呢?這個(gè)問(wèn)題的答案是Lua解釋器,即可執(zhí)行程序“l(fā)ua”。這個(gè)解釋器是一個(gè)簡(jiǎn)單的應(yīng)用程序,它依靠Lua庫(kù)來(lái)實(shí)現(xiàn)主要功能。這個(gè)程序會(huì)處理 與用戶的交互,它將用戶的文件或字符串輸入Lua庫(kù),由Lua庫(kù)來(lái)完成主要的工作,例如真正地運(yùn)行Lua代碼等。這種使用一個(gè)庫(kù)來(lái)擴(kuò)展應(yīng)用程序的能力使得Lua成為一種“擴(kuò)展語(yǔ)言”。而與此同時(shí),一個(gè)使用了Lua的程序可以在Lua環(huán)境中注冊(cè)C語(yǔ)言或其他語(yǔ)言實(shí)現(xiàn)的新函數(shù),由此就可以向Lua添加某些無(wú)法直接用Lua編寫(xiě)的功能, 這便使Lua成為一種“可擴(kuò)展的語(yǔ)言”。C API是一組能使C代碼與Lua交互的函數(shù)。其中包括讀寫(xiě)Lua全局變量、調(diào)用Lua函數(shù)、運(yùn)行一段代碼,以及注冊(cè)C函數(shù)以供Lua代碼調(diào)用等。Lua和C語(yǔ)言通信的主要方法是一個(gè)無(wú)所不在的虛擬棧。幾乎所有的API調(diào)用都會(huì)操作這個(gè)棧上的值。所有的數(shù)據(jù)交換,無(wú)論是Lua到C語(yǔ)言或C語(yǔ)言到Lua都通過(guò)這個(gè)棧 來(lái)完成。此外,還可以用這個(gè)棧來(lái)保存一些中間結(jié)果。??梢越鉀QLua和C語(yǔ)言之間存在的兩大差異,第一種差異是Lua使用垃圾收集,而C語(yǔ)言要求顯示地釋放內(nèi)存;第二種是Lua使用動(dòng)態(tài)類(lèi)型,而C語(yǔ)言使用靜態(tài)類(lèi)型。第一個(gè)示例通過(guò)一個(gè)簡(jiǎn)單的Lua解釋器程序來(lái)開(kāi)始學(xué)習(xí)C API。以下代碼是一個(gè)最原始的解釋器程序:#include <stdio.h>#include <string.h>#include "lua.h"#include "lauxlib.h"#include "lualib.h"int main(void){char buff[256];int error;lua_State *L = luaL_newstate(); //打開(kāi)LualuaL_openLibs(L); //打開(kāi)標(biāo)準(zhǔn)庫(kù)while (fgets(buff, sizeof(buff), stdin) != NULL){error = luaL_loadbuffer(L, buff, strlen(buff), "line") || lua_pcall(L, 0, 0, 0);if (error){fPRintf(stderr, "%s", lua_tostring(L, -1));lua_pop(L, 1); //從棧中彈出錯(cuò)誤消息}}lua_close(L);return 0;}頭文件lua.h定義了Lua提供的基礎(chǔ)函數(shù),包括創(chuàng)建Lua環(huán)境、調(diào)用Lua函數(shù)(如lua_pcall)、讀寫(xiě)Lua環(huán)境中全局變量,以及注冊(cè)供Lua調(diào)用的新函數(shù)等。lua.h中定義所有內(nèi)容都有一個(gè)lua_前綴。頭文件 lauxlib.h定義了輔助庫(kù)( auxiliary、library、auxlib)提供的函數(shù)。它的所有定義都以luaL_開(kāi)頭。輔助庫(kù)是一個(gè)使用lua.h中API編寫(xiě)的一個(gè)較高的抽象層。Lua的所有標(biāo)準(zhǔn)庫(kù)編寫(xiě)都用到了輔助庫(kù)?;A(chǔ)API的設(shè)計(jì)保持原子性和正交性,而輔助庫(kù)則側(cè)重于解決具體的任務(wù)。當(dāng)然,程序若要?jiǎng)?chuàng)建自己的抽象也是非常簡(jiǎn)單的。注意輔助庫(kù)并 沒(méi)有直接訪問(wèn)Lua的內(nèi)部,它都是用官方的 基礎(chǔ)API來(lái)完成所有的工作的。Lua庫(kù)中沒(méi)有定義任何全局變量。它將所有的 狀態(tài)都保存在動(dòng)態(tài)結(jié)構(gòu) lua_State中,所有的C API都要求 傳入一個(gè)指向該結(jié)構(gòu)的指針。這種實(shí)現(xiàn)使得Lua可以重入,稍加修改即可用于多線程的代碼中。luaL_newstate函數(shù)用于創(chuàng)建一個(gè)新環(huán)境(或狀態(tài))。當(dāng) luaL_newstate創(chuàng)建一個(gè)新的環(huán)境時(shí),新環(huán)境中沒(méi)有包含預(yù)定義的函數(shù),甚至沒(méi)有print。為了使Lua保持小巧,所有的標(biāo)準(zhǔn)庫(kù)都被組織到了不同的包中。這樣便可以忽略那些不需要的包。在頭文件lualib.h中定義了打開(kāi)這些庫(kù)的函數(shù),而輔助庫(kù)函數(shù) luaL_openlibs則可以打開(kāi)所有的標(biāo)準(zhǔn)庫(kù)。當(dāng)創(chuàng)建好一個(gè)狀態(tài),并在其中加載了標(biāo)準(zhǔn)庫(kù)后,就可以解釋用戶的輸入了。程序調(diào)用 luaL_loadbuffer來(lái)編譯用戶輸入的每行內(nèi)容。如果沒(méi)有錯(cuò)誤,此調(diào)用返回0,并向棧中壓入編譯后的程序塊。然后,程序調(diào)用lua_pcall,這個(gè)函數(shù)會(huì)將程序塊從棧中彈出,并在保護(hù)模式中運(yùn)行它。與 luaL_loadbuffer類(lèi)似,lua_pcall返回0表示沒(méi)有錯(cuò)誤。若發(fā)生錯(cuò)誤,那么這些函數(shù)就會(huì)向棧中壓入一條錯(cuò)誤消息。用lua_tostring可以獲取這條消息,打印后可以用 lua_pop把它從棧中刪除。Lua可以同時(shí)作為C代碼或C++代碼來(lái)編譯。某些C程序庫(kù)中 常會(huì)出現(xiàn)以下這種 調(diào)節(jié)代碼,而在lua.h中并沒(méi)有包含它們:#ifdef --cplusplusextern "C"{#endif...#ifdef --cplusplus}#endif如果將Lua作為C代碼來(lái)編譯,并在C++中使用它,那么 可以包含lua.hpp來(lái)代替lua.h。lua.hpp定義為:extern "C"{#include "lua.h"}棧在Lua和C語(yǔ)言之間交換數(shù)據(jù)時(shí),需要面對(duì)兩個(gè)問(wèn)題:1、動(dòng)態(tài)類(lèi)型和靜態(tài)類(lèi)型之間的區(qū)別;2、自動(dòng)內(nèi)存管理和手動(dòng)內(nèi)存管理之間的區(qū)別。在Lua中,當(dāng)用戶寫(xiě)a[k]=v,k和v可以是任意的類(lèi)型。甚至于a也有可能是其他類(lèi)型,因?yàn)榭梢酝ㄟ^(guò)元表重載操作符。假設(shè)要在C語(yǔ)言中提供一個(gè)API函數(shù)settable。由于C函數(shù)的參數(shù)是固定類(lèi)型,所以必須為各種類(lèi)型的參數(shù)編寫(xiě)一個(gè)settable函數(shù)。可以在C語(yǔ)言中聲明一些聯(lián)合(union)類(lèi)型來(lái)解決這個(gè)問(wèn)題。假設(shè)這種類(lèi)型叫做lua_Value,能夠表示所有的Lua值。那么settable就可以聲明為:void lua_settable(lua_Value a, lua_Value k, lua_Value v)這種做法有兩個(gè)缺點(diǎn)。首先,很難將這種復(fù)雜的類(lèi)型映射到其他語(yǔ)言中。Lua的設(shè)計(jì)目標(biāo)不僅僅是為了便于C/C++訪問(wèn),還應(yīng)該可以被java、 Fortran、C#或其他語(yǔ)言訪問(wèn)。其次,Lua采用垃圾收集機(jī)制,如果將一個(gè)Lua table保持在一個(gè)C變量中,Lua引擎則無(wú)法搜索出,因此,它會(huì)認(rèn)為這個(gè)table是垃圾文件,并回收它。由于上述原因,Lua API中沒(méi)有定義任何類(lèi)似于 lua_Value的類(lèi)型,而是使用了一個(gè)抽象的棧,在Lua和C語(yǔ)言之間交換數(shù)據(jù)。棧中的每個(gè)元素都能保存任何類(lèi)型的Lua值。要獲取Lua中的一個(gè)值時(shí),只要調(diào)用一個(gè)Lua API函數(shù),Lua就會(huì)將指定的值壓入棧中。要將一個(gè)值傳給Lua時(shí),需要先將這個(gè)值壓入棧,然后調(diào)用Lua API,Lua就會(huì)獲取該值并將其從棧中彈出。為了將C類(lèi)型的值壓入棧,或者從棧中獲取不同類(lèi)型的值,就需要為每種類(lèi)型定義一個(gè)特定的函數(shù)。但這種定義的數(shù)量遠(yuǎn)遠(yuǎn)小于上例中提到的定義settable的數(shù)量。另外,由于這個(gè)棧是Lua管理的,垃圾收集器能確定C語(yǔ)言使用哪些值。Lua嚴(yán)格按照LIFO后進(jìn)先出的規(guī)范來(lái)操作這個(gè)棧。當(dāng)調(diào)用Lua時(shí),Lua只會(huì)改變棧的頂部。不過(guò),C代碼則有更大的自由度,它可以檢索棧中間的元素,甚至在棧的任意位置插入或刪除元素。壓入元素對(duì)于每種可以呈現(xiàn)在Lua中的C類(lèi)型,API都有一個(gè)對(duì)應(yīng)的壓入函數(shù):nil lua_pushnil雙精度浮點(diǎn)數(shù) lua_pushnumber整數(shù) lua_pushinteger布爾(C語(yǔ)言中的整數(shù)) lua_pushboolean任意字符串(char*及長(zhǎng)度) lua_pushlstring零結(jié)尾的字符串 lua_pushstringvoid lua_pushnil (lua_State *L);void lua_pushboolean (lua_State *L, int bool);void lua_pushnumber (lua_State *L, lua_Number n);void lua_pushinteger (lua_State *L, lua_Integer n);void lua_pushlstring (lua_State *L, const char *s, size_t len);void lua_pushstring (lua_State *L, const char *s);類(lèi)型 lua_Number是Lua中的數(shù)字類(lèi)型。默認(rèn)為 雙精度浮點(diǎn)數(shù),但有些 發(fā)行版本為了適應(yīng)某種硬件受限的環(huán)境,會(huì)將數(shù)字類(lèi)型改 為 單精度浮點(diǎn)數(shù)或 長(zhǎng)整數(shù)。類(lèi)型lua_Integer是一種整數(shù)類(lèi)型,它足以存儲(chǔ)大型字符串的長(zhǎng)度,通常定義為ptrdiff_t類(lèi)型。Lua中的字符串不是以零結(jié)尾的,它們可以包含任意二進(jìn)制數(shù)據(jù)。因此,它們必須同時(shí)保存一個(gè)顯示的長(zhǎng)度。將字符串壓入棧的基本函數(shù)是 lua_pushlstring,它要求傳入一個(gè)顯示的長(zhǎng)度參數(shù)。對(duì)于零結(jié)尾的字符串,可以使用使用函數(shù)lua_pushstring,這個(gè)函數(shù)通過(guò)strlen來(lái)計(jì)算字符串的長(zhǎng)度。Lua不會(huì)持有指向外部字符串的指針。對(duì)于所有Lua持有的字符串,它都會(huì)生成一個(gè)內(nèi)部副本,或者復(fù)用現(xiàn)有的內(nèi)容。因此,即使在這些函數(shù)返回后立即釋放或修改這些字符串,也不會(huì)出現(xiàn)問(wèn)題。向棧中壓入一個(gè)元素時(shí),應(yīng)該確保棧中具有足夠的 空間。當(dāng)Lua啟動(dòng)時(shí),或Lua調(diào)用C語(yǔ)言時(shí),棧中至少會(huì)有20個(gè)空閑槽。這些空間對(duì)于普通的應(yīng)用是足夠了,所以一般我們無(wú)須顧及空間上的問(wèn)題。然而有些任務(wù)會(huì)需要更多的空間,例如一個(gè)具有很多參數(shù)的函數(shù),在這些情況中,就要調(diào)用 lua_checkstack來(lái)檢查棧中是否有足夠的空間:int lua_checkstack(lua *L, int sz);查詢?cè)谹PI是使用“索引”來(lái)引用棧中的元素。第一個(gè)壓入棧中的元素的索引為1;第二個(gè)壓入的元素索引為2, 以此類(lèi)推直到棧頂。還可以以棧頂為參考物,使用負(fù)數(shù)的索引來(lái)訪問(wèn)棧中的元素。此時(shí),-1表示棧頂元素(最后壓入的元素),-2表示棧頂下面的元素, 以此類(lèi)推。例如,調(diào)用lua_tostring(L, -1)會(huì)將棧頂?shù)?#20540;作為一個(gè)字符串返回。其中有些情況適用于從棧底索引棧,而另一些情況則便于使用負(fù)數(shù)索引。為了檢查一個(gè)元素是否為特定的類(lèi)型,API提供了一系列的 函數(shù)lua_is*,其中*可以是任意lua類(lèi)型。這些函數(shù)有l(wèi)ua_isnumber、lua_isstring和lua_istable等。所有這些函數(shù)都有同樣的原型:int lua_is* (lua_State *L, int index);實(shí)際上,lua_isnumber不會(huì)檢查值是否為數(shù)字類(lèi)型,而是檢查值是否能轉(zhuǎn)換為數(shù)字類(lèi)型。lua_isstring也具有同樣的行為。因此,對(duì)于任意數(shù)字,lua_isstring都返回真。還有一個(gè)函數(shù)lua_type,它會(huì)返回棧中元素的類(lèi)型。每種類(lèi)型都對(duì)應(yīng)于一個(gè)常量,這些常量定義在頭文件lua.h中,它們是LUA_TNIL,LUA_TBOOLEAN,LUA_TNUMBER,LUA_TSTRING、LUA_TTABLE、LUA_TTHREAD、 LUA_TUSERDATA和LUA_TFUNCTION。這個(gè)函數(shù)一般可用在一個(gè)switch語(yǔ)句中。另外,若要檢查一個(gè)元素是否為真正的字符串或數(shù)字(無(wú)須轉(zhuǎn)換的),也可以使用這個(gè)函數(shù)。lua_to*函數(shù)用于從棧中獲取一個(gè)值:int lua_toboolean (lua_State *L, int index);lua_Number lua_tonumber (lua_State *L, int index);lua_Integer lua_tointeger (lua_State *L, int index);const char *lua_tolstring (lua_State *L, int index, size_t *len);size_t lua_objlen (lua_State *L, int index);如果指定的元素不具有正確的類(lèi)型,調(diào)用這些函數(shù)也不會(huì)有問(wèn)題。在這種情況下, lua_toboolean、lua_tonumber、 lua_tointeger和 lua_objlen會(huì)返回0,而其他函數(shù)會(huì)返回 NULL。返回0并不是很有用,但ANSI C也沒(méi)有提供其他可以表示錯(cuò)誤的值。至于其他lua_to*函數(shù),通常不先使用lua_is*函數(shù),只需在調(diào)用它們之后測(cè)試返回結(jié)果是否為NULL就可以了。lua_tolstring函數(shù)會(huì)返回一個(gè)指向內(nèi)部字符串副本的指針,并將字符串的長(zhǎng)度存入最后一個(gè)參數(shù)len中。這個(gè)內(nèi)部副本不能修改,返回 類(lèi)型中的const也說(shuō)明了這點(diǎn)。Lua 保證只要這個(gè)對(duì)應(yīng)的字符串值還在棧中,那么這個(gè)指針就是有效的。當(dāng)Lua調(diào)用的一個(gè)C函數(shù)返回時(shí),Lua就會(huì)清空它的棧。這就形成了一條規(guī)則,不要在C函數(shù)之外使用在C函數(shù)內(nèi)獲得的指向Lua字符串的指針。所有 lua_tolstring返回字符串在其末尾都會(huì)有一個(gè)額外的零,不過(guò)這些字符串的中間也有可能會(huì)有零。字符串長(zhǎng)度通過(guò)第三個(gè)參數(shù)len返回,這才是真正的字符串長(zhǎng)度。進(jìn)一步說(shuō) ,假設(shè)棧頂?shù)?#20540;是一個(gè)字符串,如下總是為真:size_t l;const char *s = lua_tolstring(L, -1, &l); /*任何Lua字符串*/assert(s[l] == '/0');assert(strlen(s) <= l);如果不需要長(zhǎng)度信息,可以將第三個(gè)參數(shù)設(shè)為NULL來(lái)調(diào)用lua_tolstring。或者使用宏lua_tostring,這個(gè)宏就是用NULL作為第三個(gè)參數(shù)來(lái)調(diào)用lua_tolstring。lua_objlen函數(shù)可以返回一個(gè)對(duì)象的“長(zhǎng)度”。對(duì)于字符串和table,這個(gè)值是長(zhǎng)度操作符‘#’的結(jié)果。這個(gè)函數(shù)可以用于獲取一個(gè)“完全userdata”的大小。為了演示這些函數(shù)的使用,以下代碼實(shí)現(xiàn)了一個(gè)有用的輔助函數(shù),它會(huì)打印整個(gè)棧的內(nèi)容,這個(gè) 函數(shù)會(huì)由下而上地遍歷棧,并根據(jù)每個(gè)元素的類(lèi)型打印其值,字符串放在一對(duì)單引號(hào)內(nèi)打印,數(shù)字使用格式“%g”來(lái)打印,其他值(table、函數(shù)等)則只打印它們的類(lèi)型。其中, lua_typename可將一個(gè)類(lèi)型編碼轉(zhuǎn)換為一個(gè)類(lèi)型名。static void stackDump (lua_State *L){int i;int top = lua_gettop(L);for (i = 1; i <= top; ++i){//遍歷所有層int t = lua_type(L, i);switch (t){case LUA_TSTRING:{//字符串printf("'%s'", lua_tostring(L, i));break;}case LUA_TBOOLEAN:{//布爾printf(lua_toboolean(L, i) ? "true" : "false");break;}case LUA_TNUMBER:{//數(shù)字printf("%g", lua_tonumber(L, i));break;}default:{//其他值printf("%s", lua_typename(L, i));break;}}printf(" "); //打印一個(gè)分隔符}printf("/n"); //列表結(jié)尾}其他棧操作除了在C語(yǔ)言和棧之間交換數(shù)據(jù)的函數(shù)外,API還提供了以下這些用于普通棧操作的函數(shù)://返回棧中元素的個(gè)數(shù),也可以說(shuō)是棧頂元素的索引。int lua_gettop (lua_State *L);//將棧頂設(shè)置為一個(gè)指定的位置,即修改棧中元素的數(shù)量。如果之前的棧頂比新設(shè)置的更高,那么高出來(lái)的部分會(huì)被丟棄;反之,會(huì)向棧中壓入nil來(lái)補(bǔ)足大小。有一個(gè)特例,調(diào)用lua_settop(L, 0)能清空棧。也可以用負(fù)數(shù)索引 來(lái)使用 lua_settop。另外,API根據(jù)這個(gè)函數(shù)還提供了一個(gè)宏,用于從棧中彈出n個(gè)元素:#define lua_pop(L, n) lua_settop(L, -(n) - 1)void lua_settop (lua_State *L, int index);//lua_pushvalue函數(shù)會(huì)將指定索引上值的副本壓入棧。void lua_pushvalue (lua_State *L, int index);//lua_remove刪除指定索引上的元素,并將該位置之上的所有元素下移以填補(bǔ)空缺。void lua_remove (lua_State *L, int index);//lua_insert會(huì)上移指定位置之上的所有元素以開(kāi)辟一個(gè)槽的空間,然后將棧頂元素移到該位置。void lua_insert (lua_State *L, int index);//lua_replace彈出棧頂?shù)?#20540;,并將該值設(shè)置到指定索引上,但它不會(huì)移動(dòng)任何東西。void lua_replace (lua_State *L, int index);# include <stdio.h>#include "lua.h"#include "luaxlib.h"static void stackDump (lua_State *L){<如之前的示例>}int main (void){lua_State *L = luaL_newstate();lua_pushboolean(L, 1);lua_pushnumber(L, 10);lua_pushnil(L);lua_pushstring(L, "hello");stackDump(L); //true 10 nil 'hello'lua_pushvalue(L, -4);stackDump(L); //true 10 nil 'hello' truelua_replace(L, 3);stackDump(L); //true 10 true 'hello'lua_settop(L, 6);stackDump(L); //true 10 true 'hello' nil nillua_remove(L, -3);stackDump(L); //true 10 true nil nillua_settop(L, -5);stackDump(L); //truelua_close(L);return 0;}C API中的錯(cuò)誤處理C語(yǔ)言不同于C++和Java,它沒(méi)有提供異常處理機(jī)制。為了克服這個(gè)困難,Lua使用C語(yǔ)言中的setjmp機(jī)制,這是一種類(lèi)似與異常處理的機(jī)制。Lua中的所有結(jié)構(gòu)都是動(dòng)態(tài)的,它們會(huì)根據(jù) 需要來(lái)增長(zhǎng),或者縮小。在Lua中有許多地方可能會(huì)發(fā)生內(nèi)存分配錯(cuò)誤。幾乎所有的函數(shù)都要面對(duì)這種潛在的錯(cuò)誤。那么在發(fā)生錯(cuò)誤時(shí),與其讓API中的每個(gè)函數(shù)返回錯(cuò)誤代碼,不如使用異常來(lái)標(biāo)記這些錯(cuò)誤。因此,幾乎所有的API函數(shù)都會(huì)拋出錯(cuò)誤(即調(diào)用longjmp),而 不是返回錯(cuò)誤。當(dāng)編寫(xiě)庫(kù)代碼 時(shí)(被Lua調(diào)用的C函數(shù)),使用longjmp幾乎和使用異常處理機(jī)制一樣方便,Lua會(huì)捕獲所有可能的錯(cuò)誤。而當(dāng)編寫(xiě)應(yīng)用程序代碼(調(diào)用Lua的C代碼),必須提供一種捕獲錯(cuò)誤的方式。應(yīng)用程序代碼中的錯(cuò)誤處理通常情況下,應(yīng)用程序代碼是以“無(wú)保護(hù)”模式運(yùn)行的。由于它們不是由Lua調(diào)用的,Lua無(wú)法設(shè)置適當(dāng)?shù)纳舷挛膩?lái)捕獲錯(cuò)誤。因此,當(dāng)Lua發(fā)現(xiàn)了例如“內(nèi)存不足”這類(lèi)錯(cuò)誤時(shí),它基本上不會(huì) 進(jìn)行太多的處理。此時(shí),Lua會(huì)調(diào)用一個(gè)“緊急函數(shù)“,當(dāng)這個(gè)函數(shù)返回后,Lua就會(huì)結(jié)束應(yīng)用程序。用戶可以通過(guò)函數(shù)set_atpanic來(lái)設(shè)置自己的”緊急“函數(shù)。如果發(fā)生了內(nèi)存分配錯(cuò)誤,而又不想結(jié)束應(yīng)用程序,那么有兩種做法。第一種是設(shè)置一個(gè)“緊急”函數(shù),讓它不要把控制權(quán)返回給Lua。例如,可以調(diào)用longjmp轉(zhuǎn)到之前setjmp所設(shè)置的位置。第二種做法是讓代碼在“保護(hù)模式”下運(yùn)行。大多數(shù)應(yīng)用程序 (包括Lua解釋器程序)都采用第二種做法,它們調(diào)用lua_pcall來(lái)運(yùn)行Lua代碼。因而這些Lua代碼 也都是運(yùn)行在保護(hù)模式中的。如果發(fā)生了內(nèi)存分配錯(cuò)誤,lua_pcall會(huì)返回一個(gè)錯(cuò)誤代碼,并將解釋器 封固在 一致的狀態(tài)。如果要保護(hù)那些與Lua交互的C代碼,可以使用 lua_cpcall。這個(gè)函數(shù)類(lèi)似于lua_pcall,但它接受一個(gè)C函數(shù)作為參數(shù),然后調(diào)用這個(gè)C 函數(shù) 。將一個(gè)函數(shù)壓入棧中不會(huì)有內(nèi)存分配失敗的可能。庫(kù)代碼中的錯(cuò)誤處理Lua是一種安全的語(yǔ)言,無(wú)論寫(xiě)什么,寫(xiě)出來(lái)的內(nèi)容是否正確,都能用Lua自身的術(shù)語(yǔ)來(lái)理解程序的行為。此外,錯(cuò)誤也是通過(guò)Lua的 術(shù)語(yǔ)來(lái)檢測(cè)和解釋的。可以用C語(yǔ)言來(lái)做一個(gè)對(duì)比,許多C程序的錯(cuò)誤行為只能用底層硬件的術(shù)語(yǔ)來(lái)解釋?zhuān)e(cuò)誤位置則是由“程序計(jì)數(shù)器”寄存器給出的。當(dāng)將新的C函數(shù)加入Lua時(shí),就有可能打破這種安全性。例如,添加一個(gè)函數(shù)poke,它能在任意內(nèi)存地址上存儲(chǔ)任意字節(jié)。這個(gè)函數(shù)就有可能引起各種內(nèi)存破壞。因此必須確保新加入的函數(shù)對(duì)Lua是安全的,并提供良好的錯(cuò)誤處理。正如之前所說(shuō)的,每個(gè)C程序都有各自處理錯(cuò)誤的方法。然而,當(dāng)為L(zhǎng)ua 編寫(xiě)庫(kù)函數(shù)時(shí),卻只有一種標(biāo)準(zhǔn)的 錯(cuò)誤處理方法。當(dāng)一個(gè)C函數(shù)檢測(cè)到一個(gè)錯(cuò)誤時(shí),它就應(yīng)該調(diào)用lua_error。lua_error函數(shù)會(huì)清理Lua中所有需要清理的東西,然后 跳轉(zhuǎn)回發(fā)起執(zhí)行的那個(gè)lua_pcall,并附上一條錯(cuò)誤消息。
上一篇:PAT BASIC 1012

下一篇:PAT BASIC 1012

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 诸暨市| 米林县| 淮安市| 衡阳县| 贺兰县| 和静县| 兴义市| 枣庄市| 迭部县| 扶余县| 荔波县| 都安| 招远市| 广丰县| 井冈山市| 乐至县| 合水县| 克拉玛依市| 福泉市| 蒲江县| 南澳县| 寿阳县| 湄潭县| 如东县| 吉隆县| 郎溪县| 丰原市| 庐江县| 莎车县| 丰县| 绥德县| 新源县| 仁化县| 沐川县| 壤塘县| 芦溪县| 方正县| 静乐县| 会泽县| 柳江县| 林口县|