LUA_API lua_absindex

本系列不會講 Lua 的基礎(chǔ)語法,由于Lua的輕便簡潔,讀者自行搜索了解,很快就可以入門。
本節(jié)開始,將直接進(jìn)入 Lua 的 C API 探索,探索順序基本與 Lua 參考手冊一致。
因為是第一次讀 Lua 源碼,若有錯誤,尚請指教和見諒。

lua_absindex

解析

我們找到 lua_absindex 在源碼中的定義:

// lapi.c 160
/*
** convert an acceptable stack index into an absolute index
*/
LUA_API int lua_absindex (lua_State *L, int idx) {
  return (idx > 0 || ispseudo(idx))
         ? idx
         : cast_int(L->top - L->ci->func) + idx;
}

解釋下注釋:將一個可接受的索引 idx 轉(zhuǎn)換為絕對索引。
注意到實現(xiàn)中有一個函數(shù) ispseudo(idx),可以知道它用來檢驗索引是否處于可接受的范圍內(nèi)。
我們找到 ispseudo(idx) 的定義:

// lapi.c 46
#define ispseudo(i)     ((i) <= LUA_REGISTRYINDEX)

我靠,原來是一個宏定義,它的作用是將索引值 idxLUA_REGISTRYINDEX 做比較。
繼續(xù)查找 LUA_REGISTRYINDEX 的定義:

// lua.h 42
/*
** Pseudo-indices
** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty
** space after that to help overflow detection)
*/
#define LUA_REGISTRYINDEX   (-LUAI_MAXSTACK - 1000)

簡單解釋下注釋:-LUAI_MAXSTACK (注意是負(fù)值) 是棧最小的有效索引,同時 Lua 保留了一些空閑空間來檢測溢出。
我們接著來看 LUAI_MAXSTACK

// luaconf.h 705
/*
@@ LUAI_MAXSTACK limits the size of the Lua stack.
** CHANGE it if you need a different limit. This limit is arbitrary;
** its only purpose is to stop Lua from consuming unlimited stack
** space (and to reserve some numbers for pseudo-indices).
*/
#if LUAI_BITSINT >= 32
#define LUAI_MAXSTACK       1000000
#else
#define LUAI_MAXSTACK       15000
#endif

注釋里頭說:LUAI_MAXSTACK 限制了 Lua 堆棧的大小,而 LUAI_MAXSTACK 的大小則由整型數(shù)值的字節(jié)大小決定。
好,假設(shè)我們是 64 位,那么 ispssudo 就可以重寫為:

#define ispseudo(i)     ((i) <= (-1000000 - 1000))

現(xiàn)在我們知道,LUA_REGISTRYINDEX 定義為 堆棧最小的有效索引-1000,我們暫且稱之為注冊表索引
回到 lua_absindex 上來,如果索引 idx 大于 0 或者小于注冊表索引,那么其絕對索引就原樣輸出;反之,則使用 cast_int(L->top - L->ci->func) + idx 進(jìn)行輸出。
找到 cast_int 的定義:

// llimits.h 111
#define cast(t, exp)    ((t)(exp))
// llimits.h 116
#define cast_int(i) cast(int, (i))

很簡單,cast_int 就是將數(shù)據(jù)強制轉(zhuǎn)換為整型。
L->top - L->ci->func 計算的是棧頂元素索引與當(dāng)前調(diào)用函數(shù)在棧內(nèi)的索引之間的差值,根據(jù)這個差值,我們可以間接知道棧內(nèi)元素的個數(shù)。我們看獲得棧內(nèi)元素個數(shù)的函數(shù) lua_gettop 定義就知道了:

LUA_API int lua_gettop (lua_State *L) {
  return cast_int(L->top - (L->ci->func + 1));
}

現(xiàn)在,簡短的幾行代碼都得到解釋了,我們可以據(jù)此得出一個結(jié)論:當(dāng)給定輸入?yún)?shù),也即索引時,lua_absindex 的輸出預(yù)期:

  • 正數(shù):原樣輸出
  • 超出注冊表索引:原樣輸出
  • 在負(fù)數(shù)可接受索引范圍內(nèi):棧內(nèi)元素個數(shù)+1+索引

測試

  • 測試用例
#include <lua.hpp>
#include <lualib.h>
#include <lauxlib.h>
void test_lua_api_absindex(int index)
{
    lua_State *L = luaL_newstate();
    // 壓入 index 個元素
    for(int i=1; i<=index; i++)
    {
        lua_pushnumber(L, 1);
    }
    int positive = lua_absindex(L, 10);
    int pseudo   = lua_absindex(L, -1001000);
    int negative = lua_absindex(L, -100);
    printf("lab_absindex got result : \n postive = %d\npseudo = %d\nnegative = %d", positive, pseudo, negative);
}
int main(int argc, const char * argv[]) {
    test_lua_api_absindex(1000);
    return 0;
}
  • 輸出
lab_absindex got result : 
postive = 10
pseudo = -10001000
negative = 901 // 1000 + 1 - 100
Program ended with exit code: 0

結(jié)果符合我們的預(yù)期。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • C API 云風(fēng)Blog:Lua C API 的正確用法 C讀取和調(diào)用Lua文件的庫:lua.h, lauxlib...
    SysuYe閱讀 5,828評論 2 10
  • 第一篇 語言 第0章 序言 Lua僅讓你用少量的代碼解決關(guān)鍵問題。 Lua所提供的機制是C不擅長的:高級語言,動態(tài)...
    testfor閱讀 2,974評論 1 7
  • 當(dāng)在Lua和C之間交換數(shù)據(jù)時主要的問題是自動回收與手動回收內(nèi)存管理的不一致。因此,Lua 用一個抽象的棧在Lua與...
    luffier閱讀 2,755評論 0 3
  • 1. 寫在前面 很多時候我們都需要借助一些腳本語言來為我們實現(xiàn)一些動態(tài)的配置,那么就會涉及到如何讓腳本語言跟原生語...
    杰嗒嗒的阿杰閱讀 3,508評論 9 31
  • 資金流斷裂自救:賣掉一部分股份;出賣或出租一部分產(chǎn)品(更新?lián)Q代較快);適度的規(guī)模,保障最經(jīng)濟(jì)的成本。 創(chuàng)業(yè)初期應(yīng)記...
    好就不賤閱讀 600評論 0 0

友情鏈接更多精彩內(nèi)容