首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

tolua++ tolua_toxxx API 設計缺陷與正確使用模式

     編輯:關於C語言

問題背景

tolua++ 綁定層常用 tolua_tonumber、tolua_tostring 等 API 從 Lua 堆疊取參數,原型:

lua_Number tolua_tonumber(lua_State* L, int narg, lua_Number def);
const char* tolua_tostring(lua_State* L, int narg, const char* def);

直覺與實作的落差

程式設計師預期:參數缺失、型別錯誤、傳 nil 皆回傳 def。

實際實作(偷懶版):

TOLUA_API lua_Number tolua_tonumber(lua_State* L, int narg, lua_Number def) {
    return lua_gettop(L) < abs(narg) ? def : lua_tonumber(L, narg);
}
TOLUA_API const char* tolua_tostring(lua_State* L, int narg, const char* def) {
    return lua_gettop(L) < abs(narg) ? def : lua_tostring(L, narg);
}

只有「參數完全未傳(堆疊不足)」才回傳 def;傳 nil 或型別不符時,直接呼叫 Lua C API,行為為:

  • lua_tonumber:非數值 → 回傳 0
  • lua_tostring:非字串 → 回傳 NULL

血淚教訓

// 案例 1:空指標崩潰
const char* name = tolua_tostring(L, 1, "");
if (name[0] == '\0') ...  // name 可能是 NULL!

// 案例 2:靜默預設值失效
float angle = (float)tolua_tonumber(L, 1, 2*PI);  // 傳 nil → angle=0,非 2π

正確防禦模式

// 字串:雙重檢查
const char* name = tolua_tostring(L, 1, "");
if (!name || name[0] == '\0') { /* 處理缺失/空字串 */ }

// 數值:型別檢查
lua_Number angle = 0;
if (lua_isnumber(L, 1)) angle = tolua_tonumber(L, 1, 2*PI);
else angle = 2*PI;  // 明確預設

參考 Lua 標準庫做法

LUALIB_API lua_Number luaL_checknumber(lua_State* L, int narg) {
    lua_Number d = lua_tonumber(L, narg);
    if (d == 0 && !lua_isnumber(L, narg))
        luaL_argerror(L, narg, LUA_TNUMBER);  // 拋錯
    return d;
}

Lua 內部存取越界會回傳 luaO_nilobject,配合 lua_is* 可完整判斷。

建議

  • 封裝專案專屬 safe_tolua_tonumber 等安全包裝函式
  • 嚴禁直接使用裸 API 於生產碼
  • Code Review 重點檢查所有 tolua 取參數點
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved