2015-06-19 103 views
4

我對lua_next的工作原理略有困惑。用戶定義的表:Lua C++表迭代

a={["a1"]=20,["a2"]=30} 

我要打印此表與C++代碼:

inline int lua_print(lua_State* L) 
{ 
wxString wxReturnStr=wxEmptyString; 
wxString tempString=wxEmptyString; 
int nargs = lua_gettop(L); 

for (int i=1; i <= nargs; i++) 
{ 
    int type = lua_type(L, i); 
    switch (type) 
    { 

    case LUA_TNIL: 
     break; 

    case LUA_TBOOLEAN: 
     tempString<<(lua_toboolean(L, i) ? "true" : "false"); 
     break; 

    case LUA_TNUMBER: 
     tempString<<lua_tonumber(L, i); 
     break; 

     case LUA_TSTRING: 
      tempString<<lua_tostring(L, i); 
     break; 
     case LUA_TTABLE: 
     { 
      lua_pushnil(L); 
      while(lua_next(L,-2)) 
      { 
       const char* key=lua_tostring(L,-2); 
       double val=lua_tonumber(L,-1); 
       lua_pop(L,1); 
       tempString<<key<<"="<<val<<"\t"; 
      } 

      break; 
     } 

     default: 
      tempString<<lua_typename(L, type); 
     break; 
    } 

    wxReturnStr=wxReturnStr+tempString+"\n"; 
    tempString=wxEmptyString; 

} 

lua_pop(L,nargs); 

此代碼從Lua的作品非常好,當我打電話:

print(a) -- Works well 

然而,想象一下,我在Lua中有一個表格:

b={["b1"]=10, ["b2"]=15} 

如果我叫代碼爲:與如何lua_next工作如下圖

print(a,b) -- Twice prints only contents of b 

我的理解:enter image description here [版#1]

哪裏錯誤?

+0

你怎麼指定'a'和'b'? – Kyle

回答

2

該錯誤發生在lua_next(L, -2)行,因爲-2表示棧頂減一,這裏發生的是print的最後一個參數。

改爲使用lua_next(L, i)

UPD:Lua的堆棧指標如有處於發展階段走動代碼時浮動,所以一般建議是剛開/推/考慮值,並使用該t代替-n(雖然之後引腳SML int t = lua_gettop(L)指標這個特定的情況似乎是一種按鍵錯誤。)

+0

您的建議'lua_next(L,i)'有效。然而,我現在感到困惑......當我使用'lua_next(L,1)'爲i = 1時,這表示棧的底部,據我瞭解。但是,當我說'lua_pop(L,1)'這個從棧頂彈出時。我不知道它是如何工作的... – macroland

+0

@macroland一些函數將*堆棧索引*(1..top/-top ..- 1)當作參數,其他函數則使用* count *。 lua_next(),lua_tostring(),lua_getfield()採用堆棧索引。 lua_pop(),lua_concat()將*值的數量*刪除/連接在堆棧頂部。你不能從棧中彈出,這就是爲什麼lua_remove()存在的原因。如有疑問,請查閱特定功能的文檔。 – user3125367

+0

謝謝!當我們說'lua_next(L,i)'爲i = 1時,那麼它指向堆棧的底部,即絕對索引爲1的元素。然而,當我們從堆棧彈出時,我們可以彈出的唯一方法是從肯定的頂部。現在,如果我在棧上有兩個表(索引爲1的表a,索引爲2的表b),當我們運行'lua_next(L,1)'時,代碼引用表a。這個「取」來自表a的值,並推入堆棧。現在對於密鑰使用idx = -1,對於密鑰使用idx = -2是有道理的。我的理解是,然後lua_next內部做一些從堆棧中刪除表(索引1)。 – macroland

0

處理表格後忘記了lua_pop。

lua_pushnil(L); 
     while(lua_next(L,-2)) 
     { 
      const char* key=lua_tostring(L,-2); 
      double val=lua_tonumber(L,-1); 
      lua_pop(L,1); 
      tempString<<key<<"="<<val<<"\t"; 
     } 
lua_pop(L, 1); // THE FIX, pops the nil on the stack used to process the table 

這意味着,多餘的零留在堆棧上,所以在第二次迭代中,

case LUA_TNIL: 
    break; 

只是打印什麼。

關於您的堆棧的圖形表示。每個圖像下的命令代表命令被調用後的狀態。所以最後一張圖片缺少堆棧中的[Key = a2]項目。

+0

OPs while循環不會在棧上留下零,因爲lua_next消耗最初的nil並在返回0時不會推任何東西。 – user3125367

+0

您建議在塊的末尾使用'lua_pop(L,1)',我實際上已嘗試過在發佈之前,這是行不通的。例如,對於'print(a,b)',它只打印第一個參數,第二個參數在打印之前彈出。 – macroland