1. 程式人生 > >C 函式中呼叫Lua函式時,對於lua_pcall使用的困惑

C 函式中呼叫Lua函式時,對於lua_pcall使用的困惑

最近在學習使用Lua,也通過基本的語法知識完成了公司的一個關於配置檔案引數合法性檢查的小任務。雖然任務完成了,但對於一些函式的呼叫目的還是搞不明白,這兩天再次重看了Manual Reference,稍微梳理出了一點眉目,記錄在此。

首先看一段小小小程式

//test.lua

  1. function printmsg()
  2. print("hello world")
  3. end
  4. x = 10

//test.c

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <lua.h>
  4. #include <lauxlib.h>
  5. #include <lualib.h>
  6. int main(int argc, const char *argv[])
  7. {
  8. lua_State *L;
  9. if(NULL == (L = luaL_newstate()))
  10. {
  11. perror("luaL_newstate failed");
  12. return -1;
  13. }
  14. luaL_openlibs(L);
  15. if(luaL_loadfile(L, "./test.lua"))
  16. {
  17. perror("loadfile failed");
  18. return -1;
  19. }
  20. lua_pcall(L, 0, 0, 0); //一直這樣用,但是一直不明白為什麼一定要加這一句話
  21. lua_getglobal(L, "printmsg");
  22. lua_pcall(L, 0, 0, 0);
  23. lua_close(L);
  24. return 0;
  25. }


上面的程式碼就是在test.c中呼叫test.lua的函式printmsg函式

對於上面的C程式碼,我想大家都知道幾個函式的大概作用:

luaL_newstate():建立一個新的Lua虛擬機器

luaL_openlibs() :開啟一些必要的庫,比如print等

lua_loadfile():手冊上寫的是"This function uses lua_load to load the chunk in the filenamedfilename

." 而lua_load就是把編譯過的chunk放在stack的頂部。理解chunk很重要,後面會具體講到

lua_pcall : 執行棧上的函式呼叫

一開始我一直認為既然luaL_loadfile執行以後,就可以直接嗲用lua_getglobal獲得test.lua中的函式,其實不然。手冊中明確提到,lua_load把一個lua檔案當作一個chunk編譯後放到stack的棧頂,而什麼是chunk呢?chunk就是一個可執行語句的組合,可以是一個檔案也可以是一個string

“Lua handles a chunk as the body of an anonymous function with a variable number of arguments” 這是Lua對chunk也就是lua檔案的處理方式,就是認為是一個可變引數的匿名函式。也就是說,呼叫後棧上有一個匿名函式,這個函式的body就是檔案中所有的內容。

在luaL_loadfile後,呼叫lua_getop以及lua_type可以知道棧的大小為1,放在棧上的是一個fucntion型別的value。為什麼loadfile後我們不能直接獲取到printmsg這個函式呢,那是因為剛才提到的,loadfile僅僅視編譯lua檔案,並不執行這個檔案,也就是說只是在棧上形成了一個匿名函式。只有執行這個函式一次,才會使得printmsg可以通過lua_getglobal獲取,否則,全域性變數是空的。我在手冊上看到這樣一句話:Lua在執行函式的時候,函式會例項化,獲得的closure也是這個函式的最終值。其實不管視函式,還是其他型別,如果不執行的話,它們只是被編譯,並不能在程序的空間種獲取到他們,感覺就像c的庫一樣,他們的編譯檔案.so已經存在,但是如果你不呼叫它,那麼庫中所有的變數不能被例項化,呼叫者也就無法訪問。其實pringmsg和x本質是一樣的,只是他們型別不同而已。

相關推薦

luaC 函式呼叫Lua函式對於lua_pcall使用的困惑

最近在學習使用Lua,也通過基本的語法知識完成了公司的一個關於配置檔案引數合法性檢查的小任務。雖然任務完成了,但對於一些函式的呼叫目的還是搞不明白,這兩天再次重看了Manual Reference,稍微梳理出了一點眉目,記錄在此。 首先看一段小小小程式 fun

C 函式呼叫Lua函式對於lua_pcall使用的困惑

最近在學習使用Lua,也通過基本的語法知識完成了公司的一個關於配置檔案引數合法性檢查的小任務。雖然任務完成了,但對於一些函式的呼叫目的還是搞不明白,這兩天再次重看了Manual Reference,稍微梳理出了一點眉目,記錄在此。 首先看一段小小小程式 //test.lua

C++ 呼叫 Lua 函式

使用上篇的程式碼 http://blog.csdn.net/huutu/article/details/49594469 在 C++中呼叫 lua 中的函式並處理返回值 main.cpp #incl

C++建構函式呼叫虛擬函式是否有多型的效果

C++多型的一個重要應用就是虛擬函式。但是當我們再基類的建構函式中呼叫一個子類過載的虛擬函式會出現多型的效果嗎?我們具體看一下下面的例項: #include <iostream> #define P(x) std::cout<<x<<std::endl;

C++建構函式呼叫虛擬函式

談談關於建構函式中呼叫虛擬函式的情況,僅討論單繼承,不考慮虛擬繼承和多重繼承。 測試平臺:VS2013 + Win7X64 一個例子: #include <stdlib.h> #i

C/C++—— 在建構函式呼叫虛擬函式能實現多型嗎(Vptr指標初始化的過程分析)

問題引入: 比如:如果我們想在父類的建構函式中呼叫虛擬函式,當定義子類物件的時候,父類的建構函式中的虛擬函式執行的是子類中的函式。 在下面的例子中,定義子類物件的時候,在父類建構函式中的print虛擬函式執行的不是子類中的print函式,而是父類中的prin

C++ 建構函式呼叫虛擬函式

我們知道:C++中的多型使得可以根據物件的真實型別(動態型別)呼叫不同的虛擬函式。這種呼叫都是物件已經構建完成的情況。那如果在建構函式中呼叫虛擬函式,會怎麼樣呢? 有這麼一段程式碼: class A { public: A ():m_iVal(0){test();}

在建構函式/解構函式呼叫虛擬函式

先看一段在建構函式中直接呼叫虛擬函式的程式碼: 1 #include <iostream> 2 3 class Base 4 { 5 public: 6 Base() { Foo(); } ///< 列印 1 7 8

建構函式呼叫建構函式new和delete使用小結

malloc free 是C語言的函式 new delete 是C++的操作符 #include "iostream" using namespace std; //構造中呼叫構造是危險的行為

多型性---建構函式和解構函式呼叫虛擬函式

參考 C++ primer 15.4.5 /* 建構函式和解構函式中的虛擬函式 */ #include<iostream> using namespace std; class Base { public: //在建構函式和解構函式中呼叫虛擬函式,則執行自身型別定義的版本。原因是初始

為什麼不要在建構函式呼叫虛擬函式

先看一段在建構函式中直接呼叫虛擬函式的程式碼: #include <iostream> class Base { public: Base() { Foo(); } ///< 列印 1 virtual void Foo() { std:

不要在建構函式和解構函式呼叫虛擬函式

提到建構函式和解構函式,想必大家肯定是非常瞭解,但是能否在建構函式或是解構函式中呼叫虛擬函式呢? 答案是千萬不要這麼做,這麼做不會得到大家想要的結果。 首先提一下建構函式,建構函式的順序是從基類開始構造->子類,如果在基類中呼叫虛擬函式,由於建構函式基類中僅存在自身

c++程式呼叫c編譯器編譯後的函式為什麼要加extern "c"?

首先,被它修飾的目標是“extern”的。也就是告訴編譯器,其宣告的函式和變數可以在本模組或其他模組中使用。通常,在模組的標頭檔案中對本模組提供給其他模組引用的函式和全域性變數以關鍵字extern宣告。 其次,被它修飾的目標是“c”,意思是其修飾的變數和函式是按照c語言方式

Effective C++ 條款09 絕不在構造和析構過程呼叫virtual函式

本條款的內容主要講述了在子類和父類之間的構造和析構階段不要去呼叫virtual函式,因為那可能會和你預想的結果有出入。 class Transportion{ Transportion(); virtual void logTransction()const = 0;//純虛擬函式};Transp

effective c++條款09:絕不在構造和析構過程呼叫virtual函式

#include <iostream> using namespace std; class BaseClass { public: BaseClass() { cout << "BaseClass" << endl; } ~

C語言:呼叫函式實現選擇排序和字串連線

2018年11月14日 19:57:26 return 微明 閱讀數:1 個人分類: C語言

C語言呼叫靜態庫函式和動態庫函式的方式

C語言中呼叫動態庫函式的兩種方式 方式一.隱式呼叫 將動態庫的相關檔案拷貝到當前目錄下(lib、dll),然後新增以下程式碼,在程式中指定連線庫函式。 注意:第二個引數給出的是引入庫檔案(或稱“匯出庫檔案”),而不是dll。在程式執行過程中,lib將dll中需要用到的函式對映到對應的記憶

定義一個包含私有成員變數和函式的類再定義一個內部類在內部類函式訪問外部成員變數呼叫外部函式。在外部類函式建立內部類物件呼叫內部類函式

public class Test5 {         //定義包含私有成員變數和函式         private int a = 201320883;         private voi

C++類一個建構函式呼叫另一個建構函式

class A { int a; int b; int c; public: A(int aa, int bb) : a(aa), b(bb),c(0) { cout << "aa bb" << endl; } A(int aa, in