青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

每天早晨叫醒你的不是鬧鐘,而是夢想

  C++博客 :: 首頁 :: 聯系 :: 聚合  :: 管理
  62 Posts :: 0 Stories :: 5 Comments :: 0 Trackbacks

常用鏈接

留言簿(1)

我參與的團隊

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

2014年2月17日 #

原文出自程序人生 >> C++中的返回值優化(return value optimization)
返回值優化(Return Value Optimization,簡稱RVO),是這么一種優化機制:當函數需要返回一個對象的時候,如果自己創建一個臨時對象用戶返回,那么這個臨時對象會消耗一個構造函數(Constructor)的調用、一個復制構造函數的調用(Copy Constructor)以及一個析構函數(Destructor)的調用的代價。而如果稍微做一點優化,就可以將成本降低到一個構造函數的代價,下面是在Visual Studio 2008的Debug模式下做的一個測試:(在GCC下測試的時候可能編譯器自己進行了RVO優化,看不到兩種代碼的區別)

 1 // C++ Return Value Optimization
 2 // 作者:代碼瘋子
 3 // 博客:http://www.programlife.net/
 4 #include <iostream>
 5 using namespace std;
 6  
 7 class Rational
 8 {
 9 public:
10     Rational(int numerator = 0, int denominator = 1) : 
11       n(numerator), d(denominator)
12       {
13           cout << "Constructor Called" << endl;
14       }
15       ~Rational()
16       {
17           cout << "Destructor Called" << endl;
18       }
19       Rational(const Rational& rhs)
20       {
21           this->d = rhs.d;
22           this->n = rhs.n;
23           cout << "Copy Constructor Called" << endl;
24       }
25       int numerator() const { return n; }
26       int denominator() const { return d; }
27 private:
28     int n, d;
29 };
30  
31 //const Rational operator*(const Rational& lhs,
32 //                         const Rational& rhs)
33 //{
34 //    return Rational(lhs.numerator() * rhs.numerator(),
35 //                    lhs.denominator() * rhs.denominator());
36 //}
37  
38 const Rational operator*(const Rational& lhs,
39                          const Rational& rhs)
40 {
41     cout << "----------- Enter operator* -----------" << endl;
42     Rational tmp(lhs.numerator() * rhs.numerator(),
43         lhs.denominator() * rhs.denominator());
44     cout << "----------- Leave operator* -----------" << endl;
45     return tmp;
46 }
47  
48 int main(int argc, char **argv)
49 {
50     Rational x(1, 5), y(2, 9);
51     Rational z = x * y;
52     cout << "calc result: " << z.numerator() 
53         << "/" << z.denominator() << endl;
54  
55     return 0;
56 }

函數輸出截圖如下:
Return Value Optimization
可以看到消耗一個構造函數(Constructor)的調用、一個復制構造函數的調用(Copy Constructor)以及一個析構函數(Destructor)的調用的代價。

而如果把operator*換成另一種形式:

1 const Rational operator*(const Rational& lhs,
2                 const Rational& rhs)
3 {
4     return Rational(lhs.numerator() * rhs.numerator(),
5                 lhs.denominator() * rhs.denominator());
6 }



就只會消耗一個構造函數的成本了:
返回值優化
posted @ 2014-02-17 18:20 沛沛 閱讀(308) | 評論 (0)編輯 收藏

本文最初發表于程序人生 >> Copy On Write(寫時復制) 作者:代碼瘋子

Copy On Write(寫時復制)是在編程中比較常見的一個技術,面試中也會偶爾出現(好像Java中就經常有字符串寫時復制的筆試題),今天在看《More Effective C++》的引用計數時就講到了Copy On Write——寫時復制。下面簡單介紹下Copy On Write(寫時復制),我們假設STL中的string支持寫時復制(只是假設,具體未經考證,這里以Mircosoft Visual Studio 6.0為例,如果有興趣,可以自己翻閱源碼)

Copy On Write(寫時復制)的原理是什么?
有一定經驗的程序員應該都知道Copy On Write(寫時復制)使用了“引用計數”,會有一個變量用于保存引用的數量。當第一個類構造時,string的構造函數會根據傳入的參數從堆上分配內存,當有其它類需要這塊內存時,這個計數為自動累加,當有類析構時,這個計數會減一,直到最后一個類析構時,此時的引用計數為1或是0,此時,程序才會真正的Free這塊從堆上分配的內存。
引用計數就是string類中寫時才拷貝的原理!

什么情況下觸發Copy On Write(寫時復制)
很顯然,當然是在共享同一塊內存的類發生內容改變時,才會發生Copy On Write(寫時復制)。比如string類的[]、=、+=、+等,還有一些string類中諸如insert、replace、append等成員函數等,包括類的析構時。

示例代碼:

// 作者:代碼瘋子 
// 博客:http://www.programlife.net/
// 引用計數 & 寫時復制
#include <iostream>
#include <string>
using namespace std;  
int main(int argc, char **argv)
{
   string sa = "Copy on write";
   string sb = sa;
   string sc = sb;
   printf("sa char buffer address: 0x%08X\n", sa.c_str());
   printf("sb char buffer address: 0x%08X\n", sb.c_str());
   printf("sc char buffer address: 0x%08X\n", sc.c_str());  
   sc = "Now writing..."; printf("After writing sc:\n");
   printf("sa char buffer address: 0x%08X\n", sa.c_str());
   printf("sb char buffer address: 0x%08X\n", sb.c_str());
   printf("sc char buffer address: 0x%08X\n", sc.c_str());  
   return 0;
}
輸出結果如下(VC 6.0):

Copy On Write(寫時復制)
可以看到,VC6里面的string是支持寫時復制的,但是我的Visual Studio 2008就不支持這個特性(Debug和Release都是):
Visual Studio 2008不支持Copy On Write(寫時復制)

拓展閱讀:(摘自《Windows Via C/C++》5th Edition,不想看英文可以看中文的PDF,中文版第442頁)
Static Data Is Not Shared by Multiple Instances of an Executable or a DLL

posted @ 2014-02-17 18:15 沛沛 閱讀(651) | 評論 (0)編輯 收藏

http://apt.jenslody.de/



# 打開軟件源配置文件添加下面5行
sudo gedit /etc/apt/sources.list

deb http://apt.jenslody.de/ any main
deb-src http://apt.jenslody.de/ any main
deb http://apt.jenslody.de/ any release
deb-src http://apt.jenslody.de/ any release
deb http://apt.wxwidgets.org/ lenny-wx main

# 更新軟件源配置文件 和 安裝Key
sudo apt-get update
sudo apt-get install jens-lody-debian-keyring
wget -q http://apt.wxwidgets.org/key.asc -O- | sudo apt-key add -


這樣只是把軟件源家進去了,并沒有安裝好,所以還要輸入安裝命令
# 然后輸入下面這個命令開始安裝 codeblocks
sudo apt-get install codeblocks



現在安裝好,從編程軟件里開啟CodeBlocks了,是英文的,并且是最近幾日的最版本


# 你也可以直接下載 CodeBlocks 的二進制發行包,從這個URL進入
http://apt.jenslody.de/pool/


# 中文化CodeBlocks 下載這個包,語言文件 Linux下通用的
http://srgb.googlecode.com/files/CodeBlocks_Linux_Install.zip

進入壓縮包把語言文件放到桌面 '/locale/zh_CN/CodeBlocks.mo'  
中文化 codeblocks locale/zh_CN/codeblocks.mo 里的 中文化文件放這里
 '/usr/share/codeblocks/locale/zh_CN/codeblocks.mo'  
設置權限為所有人可以訪問




# 使用管理員權限把 語言包 locale 目錄 拉到 /usr/share/codeblocks里
sudo nautilus /usr/share/codeblocks/
注意 locale 的權限可能不完整,所以 選住目錄 所有者-群組-其他設定都能訪問文件;
對包含的文件應用權限;
進入 /usr/share/codeblocks/locale/zh_CN/ 目錄選兩個文件
右鍵修改權限 所有者 和 群組 都可以讀寫




現在安裝的 CodeBlocks 打開是中文里,但是只有基本IDE環境,很多插件和開發包沒安裝
可以輸入 sudo apt-get install codeblocks <按兩下TAB>
列出沒有安裝的其他包, 你可以選擇安裝,我偷懶了
sudo apt-get install codeblocks* <回車>
sudo apt-get install libwxsmith* <回車>
sudo apt-get install libwxgtk2.8-dev <回車>


現在開啟CB,建立一個wx項目,編譯,可以編譯成功了
posted @ 2014-02-17 18:10 沛沛 閱讀(263) | 評論 (0)編輯 收藏

   在Lua中可以通過自定義類型的方式與C語言代碼更高效、更靈活的交互。這里我們通過一個簡單完整的示例來學習一下Lua中userdata的使用方式。需要說明的是,該示例完全來自于Programming in Lua。其功能是用C程序實現一個Lua的布爾數組,以提供程序的執行效率。見下面的代碼和關鍵性注釋。   

復制代碼
  1 #include <lua.hpp>   
2
#include <lauxlib.h>
3
#include <lualib.h>
4
#include <limits.h>
5

6
#define BITS_PER_WORD (CHAR_BIT * sizeof(int))
7
#define I_WORD(i) ((unsigned int)(i))/BITS_PER_WORD
8
#define I_BIT(i) (1 << ((unsigned int)(i)%BITS_PER_WORD))
9

10
typedef struct NumArray {
11
int size; 12 unsigned int values[1];
13
} NumArray;
14

15
extern "C" int newArray(lua_State* L)
16
{
17
//1. 檢查第一個參數是否為整型。以及該參數的值是否大于等于1.
18
int n = luaL_checkint(L,1);
19
luaL_argcheck(L, n >= 1, 1, "invalid size.");
20
size_t nbytes = sizeof(NumArray) + I_WORD(n - 1) * sizeof(int);
21
//2. 參數表示Lua為userdata分配的字節數。同時將分配后的userdata對象壓入棧中。
22
NumArray* a = (NumArray*)lua_newuserdata(L,nbytes);
23
a->size = n;
24
for (int i = 0; i < I_WORD(n - 1); ++i)
25
a->values[i] = 0;
26
//獲取注冊表變量myarray,該key的值為metatable。
27
luaL_getmetatable(L,"myarray");
28
//將userdata的元表設置為和myarray關聯的table。同時將棧頂元素彈出。
29
lua_setmetatable(L,-2);
30
return 1;
31
}
32

33
extern "C" int setArray(lua_State* L)
34
{
35
//1. Lua傳給該函數的第一個參數必須是userdata,該對象的元表也必須是注冊表中和myarray關聯的table。
36
//否則該函數報錯并終止程序。
37
NumArray* a = (NumArray*)luaL_checkudata(L,1,"myarray");
38
int index = luaL_checkint(L,2) - 1;
39
//2. 由于任何類型的數據都可以成為布爾值,因此這里使用any只是為了確保有3個參數。
40
luaL_checkany(L,3);
41
luaL_argcheck(L,a != NULL,1,"'array' expected.");
42
luaL_argcheck(L,0 <= index && index < a->size,2,"index out of range.");
43
if (lua_toboolean(L,3))
44
a->values[I_WORD(index)] |= I_BIT(index);
45
else
46
a->values[I_WORD(index)] &= ~I_BIT(index);
47
return 0;
48
}
49

50
extern "C" int getArray(lua_State* L)
51
{
52
NumArray* a = (NumArray*)luaL_checkudata(L,1,"myarray");
53
int index = luaL_checkint(L,2) - 1;
54
luaL_argcheck(L, a != NULL, 1, "'array' expected.");
55
luaL_argcheck(L, 0 <= index && index < a->size,2,"index out of range");
56
lua_pushboolean(L,a->values[I_WORD(index)] & I_BIT(index));
57
return 1;
58
}
59

60
extern "C" int getSize(lua_State* L)
61
{
62
NumArray* a = (NumArray*)luaL_checkudata(L,1,"myarray");
63
luaL_argcheck(L,a != NULL,1,"'array' expected.");
64
lua_pushinteger(L,a->size);
65
return 1;
66
}
67

68
extern "C" int array2string(lua_State* L)
69
{
70
NumArray* a = (NumArray*)luaL_checkudata(L,1,"myarray");
71
lua_pushfstring(L,"array(%d)",a->size);
72
return 1;
73
}
74

75
static luaL_Reg arraylib_f [] = {
76
{"new", newArray},
77
{NULL, NULL}
78
};
79

80
static luaL_Reg arraylib_m [] = {
81
{"set", setArray},
82
{"get", getArray},
83
{"size", getSize},
84
{"__tostring", array2string}, //print(a)時Lua會調用該元方法。
85
{NULL, NULL}
86
};
87

88
extern "C" __declspec(dllexport)
89
int luaopen_testuserdata(lua_State* L)
90
{
91
//1. 創建元表,并將該元表指定給newArray函數新創建的userdata。在Lua中userdata也是以table的身份表現的。
92
//這樣在調用對象函數時,可以通過驗證其metatable的名稱來確定參數userdata是否合法。
93
luaL_newmetatable(L,"myarray");
94
lua_pushvalue(L,-1);
95 //2. 為了實現面對對象的調用方式,需要將元表的__index字段指向自身,同時再將arraylib_m數組中的函數注冊到
96
//元表中,之后基于這些注冊函數的調用就可以以面向對象的形式調用了。
97
//lua_setfield在執行后會將棧頂的table彈出。
98
lua_setfield(L,-2,"__index");
99
//將這些成員函數注冊給元表,以保證Lua在尋找方法時可以定位。NULL參數表示將用棧頂的table代替第二個參數。
100 luaL_register(L,NULL,arraylib_m);
101 //這里只注冊的工廠方法。
102 luaL_register(L,"testuserdata",arraylib_f);
103 return 1;
104 }
復制代碼

  輕量級userdata: 
  之前介紹的是full userdata,Lua還提供了另一種輕量級userdata(light userdata)。事實上,輕量級userdata僅僅表示的是C指針的值,即(void*)。由于它只是一個值,所以不用創建。如果需要將一個輕量級userdata放入棧中,調用lua_pushlightuserdata即可。full userdata和light userdata之間最大的區別來自于相等性判斷,對于一個full userdata,它只是與自身相等,而light userdata則表示為一個C指針,因此,它與所有表示同一指針的light userdata相等。再有就是light userdata不會受到垃圾收集器的管理,使用時就像一個普通的整型數字一樣。

posted @ 2014-02-17 17:50 沛沛 閱讀(490) | 評論 (0)編輯 收藏

     摘要:  1. 數組操作:    在Lua中,“數組”只是table的一個別名,是指以一種特殊的方法來使用table。出于性能原因,Lua的C API為數組操作提供了專門的函數,如:    void lua_rawgeti(lua_State* L, int index, int key);  ...  閱讀全文
posted @ 2014-02-17 17:45 沛沛 閱讀(287) | 評論 (0)編輯 收藏

 Lua可以調用C函數的能力將極大的提高Lua的可擴展性和可用性。對于有些和操作系統相關的功能,或者是對效率要求較高的模塊,我們完全可以通過C函數來實現,之后再通過Lua調用指定的C函數。對于那些可被Lua調用的C函數而言,其接口必須遵循Lua要求的形式,即typedef int (*lua_CFunction)(lua_State* L)。簡單說明一下,該函數類型僅僅包含一個表示Lua環境的指針作為其唯一的參數,實現者可以通過該指針進一步獲取Lua代碼中實際傳入的參數。返回值是整型,表示該C函數將返回給Lua代碼的返回值數量,如果沒有返回值,則return 0即可。需要說明的是,C函數無法直接將真正的返回值返回給Lua代碼,而是通過虛擬棧來傳遞Lua代碼和C函數之間的調用參數和返回值的。這里我們將介紹兩種Lua調用C函數的規則。
    1. C函數作為應用程序的一部分。

復制代碼
1 #include <stdio.h>  
2
#include <string.h>
3
#include <lua.hpp>
4
#include <lauxlib.h>
5
#include <lualib.h>
6

7
//待Lua調用的C注冊函數。
8
static int add2(lua_State* L)
9
{
10 //檢查棧中的參數是否合法,1表示Lua調用時的第一個參數(從左到右),依此類推。
11 //如果Lua代碼在調用時傳遞的參數不為number,該函數將報錯并終止程序的執行。
12 double op1 = luaL_checknumber(L,1);
13 double op2 = luaL_checknumber(L,2);
14 //將函數的結果壓入棧中。如果有多個返回值,可以在這里多次壓入棧中。
15 lua_pushnumber(L,op1 + op2);
16 //返回值用于提示該C函數的返回值數量,即壓入棧中的返回值數量。
17 return 1;
18 }
19
20 //另一個待Lua調用的C注冊函數。
21 static int sub2(lua_State* L)
22 {
23 double op1 = luaL_checknumber(L,1);
24 double op2 = luaL_checknumber(L,2);
25 lua_pushnumber(L,op1 - op2);
26 return 1;
27 }
28
29 const char* testfunc = "print(add2(1.0,2.0)) print(sub2(20.1,19))";
30
31 int main()
32 {
33 lua_State* L = luaL_newstate();
34 luaL_openlibs(L);
35 //將指定的函數注冊為Lua的全局函數變量,其中第一個字符串參數為Lua代碼
36 //在調用C函數時使用的全局函數名,第二個參數為實際C函數的指針。
37 lua_register(L, "add2", add2);
38 lua_register(L, "sub2", sub2);
39 //在注冊完所有的C函數之后,即可在Lua的代碼塊中使用這些已經注冊的C函數了。
40 if (luaL_dostring(L,testfunc))
41 printf("Failed to invoke.\n");
42 lua_close(L); 43 return 0; 44 }
復制代碼

    2. C函數庫成為Lua的模塊。
    將包含C函數的代碼生成庫文件,如Linux的so,或Windows的DLL,同時拷貝到Lua代碼所在的當前目錄,或者是LUA_CPATH環境變量所指向的目錄,以便于Lua解析器可以正確定位到他們。在我當前的Windows系統中,我將其copy到"C:\Program Files\Lua\5.1\clibs\",這里包含了所有Lua可調用的C庫。見如下C語言代碼和關鍵性注釋:

復制代碼
1 #include <stdio.h>  
2
#include <string.h>
3
#include <lua.hpp>
4
#include <lauxlib.h>
5
#include <lualib.h>
6

7
//待注冊的C函數,該函數的聲明形式在上面的例子中已經給出。
8
//需要說明的是,該函數必須以C的形式被導出,因此extern "C"是必須的。
9
//函數代碼和上例相同,這里不再贅述。
10 extern "C" int add(lua_State* L)
11 { 12 double op1 = luaL_checknumber(L,1);
13 double op2 = luaL_checknumber(L,2);
14 lua_pushnumber(L,op1 + op2);
15 return 1;
16 }
17
18 extern "C" int sub(lua_State* L)
19 {
20 double op1 = luaL_checknumber(L,1);
21 double op2 = luaL_checknumber(L,2);
22 lua_pushnumber(L,op1 - op2);
23 return 1;
24 }
25
26 //luaL_Reg結構體的第一個字段為字符串,在注冊時用于通知Lua該函數的名字。
27 //第一個字段為C函數指針。
28 //結構體數組中的最后一個元素的兩個字段均為NULL,用于提示Lua注冊函數已經到達數組的末尾。
29 static luaL_Reg mylibs[] = {
30 {"add", add},
31 {"sub", sub},
32 {NULL, NULL}
33 };
34
35 //該C庫的唯一入口函數。其函數簽名等同于上面的注冊函數。見如下幾點說明:
36 //1. 我們可以將該函數簡單的理解為模塊的工廠函數。
37 //2. 其函數名必須為luaopen_xxx,其中xxx表示library名稱。Lua代碼require "xxx"需要與之對應。
38 //3. 在luaL_register的調用中,其第一個字符串參數為模塊名"xxx",第二個參數為待注冊函數的數組。
39 //4. 需要強調的是,所有需要用到"xxx"的代碼,不論C還是Lua,都必須保持一致,這是Lua的約定,
40 // 否則將無法調用。
41 extern "C" __declspec(dllexport)
42 int luaopen_mytestlib(lua_State* L)
43 {
44 const char* libName = "mytestlib";
45 luaL_register(L,libName,mylibs);
46 return 1;
47 }
復制代碼

    見如下Lua代碼:

1 require "mytestlib"  --指定包名稱 
2
3 --在調用時,必須是package.function
4 print(mytestlib.add(1.0,2.0))
5 print(mytestlib.sub(20.1,19))
posted @ 2014-02-17 17:45 沛沛 閱讀(317) | 評論 (0)編輯 收藏

     摘要:  1. 基礎:    Lua的一項重要用途就是作為一種配置語言。現在從一個簡單的示例開始吧。    --這里是用Lua代碼定義的窗口大小的配置信息    width = 200    height = 300    下面是讀取配置信息的C/...  閱讀全文
posted @ 2014-02-17 17:44 沛沛 閱讀(365) | 評論 (0)編輯 收藏

   Lua是一種嵌入式腳本語言,即Lua不是可以單獨運行的程序,在實際應用中,主要存在兩種應用形式。第一種形式是,C/C++作為主程序,調用Lua代碼,此時可以將Lua看做“可擴展的語言”,我們將這種應用稱為“應用程序代碼”。第二種形式是Lua具有控制權,而C/C++代碼則作為Lua的“庫代碼”。在這兩種形式中,都是通過Lua提供的C API完成兩種語言之間的通信的。

    1. 基礎知識:
    C API是一組能使C/C++代碼與Lua交互的函數。其中包括讀寫Lua全局變量、調用Lua函數、運行一段Lua代碼,以及注冊C函數以供Lua代碼調用等。這里先給出一個簡單的示例代碼:

復制代碼
 1 #include <stdio.h>
2 #include <string.h>
3 #include <lua.hpp>
4 #include <lauxlib.h>
5 #include <lualib.h>
6
7 int main(void)
8 {
9 const char* buff = "print(\"hello\")";
10 int error;
11 lua_State* L = luaL_newstate();
12 luaL_openlibs(L);
13
14 error = luaL_loadbuffer(L,buff,strlen(buff),"line") || lua_pcall(L,0,0,0);
15 int s = lua_gettop(L);
16 if (error) {
17 fprintf(stderr,"%s",lua_tostring(L,-1));
18 lua_pop(L,1);
19 }
20 lua_close(L);
21 return 0;
22 }
復制代碼

    下面是針對以上代碼給出的具體解釋:
    1). 上面的代碼是基于我的C++工程,而非C工程,因此包含的頭文件是lua.hpp,如果是C工程,可以直接包含lua.h。
    2). Lua庫中沒有定義任何全局變量,而是將所有的狀態都保存在動態結構lua_State中,后面所有的C API都需要該指針作為第一個參數。
    3). luaL_openlibs函數是用于打開Lua中的所有標準庫,如io庫、string庫等。
    4). luaL_loadbuffer編譯了buff中的Lua代碼,如果沒有錯誤,則返回0,同時將編譯后的程序塊壓入虛擬棧中。
    5). lua_pcall函數會將程序塊從棧中彈出,并在保護模式下運行該程序塊。執行成功返回0,否則將錯誤信息壓入棧中。
    6). lua_tostring函數中的-1,表示棧頂的索引值,棧底的索引值為1,以此類推。該函數將返回棧頂的錯誤信息,但是不會將其從棧中彈出。
    7). lua_pop是一個宏,用于從虛擬棧中彈出指定數量的元素,這里的1表示僅彈出棧頂的元素。
    8). lua_close用于釋放狀態指針所引用的資源。

    2. 棧:
    在Lua和C語言之間進行數據交換時,由于兩種語言之間有著較大的差異,比如Lua是動態類型,C語言是靜態類型,Lua是自動內存管理,而C語言則是手動內存管理。為了解決這些問題,Lua的設計者使用了虛擬棧作為二者之間數據交互的介質。在C/C++程序中,如果要獲取Lua的值,只需調用Lua的C API函數,Lua就會將指定的值壓入棧中。要將一個值傳給Lua時,需要先將該值壓入棧,然后調用Lua的C API,Lua就會獲取該值并將其從棧中彈出。為了可以將不同類型的值壓入棧,以及從棧中取出不同類型的值,Lua為每種類型均設定了一個特定函數。
    1). 壓入元素:
    Lua針對每種C類型,都有一個C API函數與之對應,如:
    void lua_pushnil(lua_State* L);  --nil值
    void lua_pushboolean(lua_State* L, int b); --布爾值
    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);  --以零結尾的字符串,其長度可由strlen得出。
    對于字符串數據,Lua不會持有他們的指針,而是調用在API時生成一個內部副本,因此,即使在這些函數返回后立刻釋放或修改這些字符串指針,也不會有任何問題。
    在向棧中壓入數據時,可以通過調用下面的函數判斷是否有足夠的棧空間可用,一般而言,Lua會預留20個槽位,對于普通應用來說已經足夠了,除非是遇到有很多參數的函數。
    int lua_checkstack(lua_State* L, int extra) --期望得到extra數量的空閑槽位,如果不能擴展并獲得,返回false。 
    
    2). 查詢元素:
    API使用“索引”來引用棧中的元素,第一個壓入棧的為1,第二個為2,依此類推。我們也可以使用負數作為索引值,其中-1表示為棧頂元素,-2為棧頂下面的元素,同樣依此類推。
    Lua提供了一組特定的函數用于檢查返回元素的類型,如:
    int lua_isboolean (lua_State *L, int index);
    int lua_iscfunction (lua_State *L, int index);
    int lua_isfunction (lua_State *L, int index);
    int lua_isnil (lua_State *L, int index);
    int lua_islightuserdata (lua_State *L, int index);
    int lua_isnumber (lua_State *L, int index);
    int lua_isstring (lua_State *L, int index);
    int lua_istable (lua_State *L, int index);
    int lua_isuserdata (lua_State *L, int index);
    以上函數,成功返回1,否則返回0。需要特別指出的是,對于lua_isnumber而言,不會檢查值是否為數字類型,而是檢查值是否能轉換為數字類型。
    Lua還提供了一個函數lua_type,用于獲取元素的類型,函數原型如下:
    int lua_type (lua_State *L, int index);
    該函數的返回值為一組常量值,分別是:LUA_TNIL、LUA_TNUMBER、LUA_TBOOLEAN、LUA_TSTRING、LUA_TTABLE、LUA_TFUNCTION、LUA_TUSERDATA、LUA_TTHREAD和LUA_TLIGHTUSERDATA。這些常量通常用于switch語句中。
    除了上述函數之外,Lua還提供了一組轉換函數,如:
    int lua_toboolean (lua_State *L, int index);
    lua_CFunction lua_tocfunction (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);
    lua_Number lua_tonumber (lua_State *L, int index);
    const void *lua_topointer (lua_State *L, int index);
    const char *lua_tostring (lua_State *L, int index);
    void *lua_touserdata (lua_State *L, int index);
    --string類型返回字符串長度,table類型返回操作符'#'等同的結果,userdata類型返回分配的內存塊長度。
    size_t lua_objlen (lua_State *L, int index); 
    對于上述函數,如果調用失敗,lua_toboolean、lua_tonumber、lua_tointeger和lua_objlen均返回0,而其他函數則返回NULL。在很多時候0不是一個很有效的用于判斷錯誤的值,但是ANSI C沒有提供其他可以表示錯誤的值。因此對于這些函數,在有些情況下需要先使用lua_is*系列函數判斷是否類型正確,而對于剩下的函數,則可以直接通過判斷返回值是否為NULL即可。
    對于lua_tolstring函數返回的指向內部字符串的指針,在該索引指向的元素被彈出之后,將無法保證仍然有效。該函數返回的字符串末尾均會有一個尾部0。
    下面將給出一個工具函數,可用于演示上面提到的部分函數,如:

復制代碼
 1 static void stackDump(lua_State* L) 
2 {
3 int top = lua_gettop(L);
4 for (int i = 1; i <= top; ++i) {
5 int t = lua_type(L,i);
6 switch(t) {
7 case LUA_TSTRING:
8 printf("'%s'",lua_tostring(L,i));
9 break;
10 case LUA_TBOOLEAN:
11 printf(lua_toboolean(L,i) ? "true" : "false");
12 break;
13 case LUA_TNUMBER:
14 printf("%g",lua_tonumber(L,i));
15 break;
16 default:
17 printf("%s",lua_typename(L,t));
18 break;
19 }
20 printf("");
21 }
22 printf("\n");
23 }
復制代碼

    3). 其它棧操作函數:
    除了上面給出的數據交換函數之外,Lua的C API還提供了一組用于操作虛擬棧的普通函數,如:
    int lua_gettop(lua_State* L); --返回棧中元素的個數。
    void lua_settop(lua_State* L, int index); --將棧頂設置為指定的索引值。
    void lua_pushvalue(lua_State* L, int index); --將指定索引的元素副本壓入棧。
    void lua_remove(lua_State* L, int index); --刪除指定索引上的元素,其上面的元素自動下移。
    void lua_insert(lua_State* L, int index); --將棧頂元素插入到該索引值指向的位置。
    void lua_replace(lua_State* L, int index); --彈出棧頂元素,并將該值設置到指定索引上。
    Lua還提供了一個宏用于彈出指定數量的元素:#define lua_pop(L,n)  lua_settop(L, -(n) - 1)    
    見如下示例代碼:

復制代碼
 1 int main()
2 {
3 lua_State* L = luaL_newstate();
4 lua_pushboolean(L,1);
5 lua_pushnumber(L,10);
6 lua_pushnil(L);
7 lua_pushstring(L,"hello");
8 stackDump(L); //true 10 nil 'hello'
9
10 lua_pushvalue(L,-4);
11 stackDump(L); //true 10 nil 'hello' true
12
13 lua_replace(L,3);
14 stackDump(L); //true 10 true 'hello'
15
16 lua_settop(L,6);
17 stackDump(L); //true 10 true 'hello' nil nil
18
19 lua_remove(L,-3);
20 stackDump(L); //true 10 true nil nil
21
22 lua_settop(L,-5);
23 stackDump(L); //true
24
25 lua_close(L);
26 return 0;
27 }
復制代碼


    3. C API中的錯誤處理:
    1). C程序調用Lua代碼的錯誤處理:
    通常情況下,應用程序代碼是以“無保護”模式運行的。因此,當Lua發現“內存不足”這類錯誤時,只能通過調用“緊急”函數來通知C語言程序,之后在結束應用程序。用戶可通過lua_atpanic來設置自己的“緊急”函數。如果希望應用程序代碼在發生Lua錯誤時不會退出,可通過調用lua_pcall函數以保護模式運行Lua代碼。這樣再發生內存錯誤時,lua_pcall會返回一個錯誤代碼,并將解釋器重置為一致的狀態。如果要保護與Lua的C代碼,可以使用lua_cpall函數,它將接受一個C函數作為參數,然后調用這個C函數。
    
    2). Lua調用C程序:
    通常而言,當一個被Lua調用的C函數檢測到錯誤時,它就應該調用lua_error,該函數會清理Lua中所有需要清理的資源,然后跳轉回發起執行的那個lua_pcall,并附上一條錯誤信息。

posted @ 2014-02-17 17:44 沛沛 閱讀(331) | 評論 (0)編輯 收藏

  Lua為了保證高度的可移植性,因此,它的標準庫僅僅提供了非常少的功能,特別是和OS相關的庫。但是Lua還提供了一些擴展庫,比如Posix庫等。對于文件操作而言,該庫僅提供了os.rename函數和os.remove函數。
    
    1. 日期和時間:
    在Lua中,函數timedate提供了所有的日期和時間功能。
    如果不帶任何參數調用time函數,它將以數字形式返回當前的日期和時間。如果以一個table作為參數,它將返回一個數字,表示該table中所描述的日期和時間。該table的有效字段如下:

字段名描述
year一個完整的年份
month01-12
day01-31
hour00-23
min00-59
sec00-59
isdst布爾值,true表示夏令時

    print(os.time{year = 1970, month = 1, day = 1, hour = 8, min = 0}) --北京是東八區,所以hour等于時表示UTC的0。
    print(os.time())  --輸出當前時間距離1970-1-1 00:00:00所經過的秒數。輸出值為 1333594721
    函數date是time的反函數,即可以將time返回的數字值轉換為更高級的可讀格式,其第一個參數是格式化字符串,表示期望的日期返回格式,第二個參數是日期和時間的數字,缺省為當前日期和時間。如:

復制代碼
 1 dd = os.date("*t",os.time())  --如果格式化字符串為"*t",函數將返回table形式的日期對象。如果為"!*t",則表示為UTC時間格式。
2 print("year = " .. dd.year)
3 print("month = " .. dd.month)
4 print("day = " .. dd.day)
5 print("weekday = " .. dd.wday) --一個星期中的第幾天,周日是第一天
6 print("yearday = " .. dd.yday) --一年中的第幾天,1月1日是第一天
7 print("hour = " .. dd.hour)
8 print("min = " .. dd.min)
9 print("sec = " .. dd.sec)
10
11 --[[
12 year = 2012
13 month = 4
14 day = 5
15 weekday = 5
16 yearday = 96
17 hour = 11
18 min = 13
19 sec = 44
20 --]]
復制代碼

    date函數的格式化標識和C運行時庫中的strftime函數的標識完全相同,見下表:

關鍵字描述
%a一星期中天數的縮寫,如Wed
%A一星期中天數的全稱,如Friday
%b月份的縮寫,如Sep
%B月份的全稱,如September
%c日期和時間
%d一個月中的第幾天(01-31)
%H24小時制中的小時數(00-23)
%I12小時制中的小時數(01-12)
%j一年中的第幾天(001-366)
%M分鐘(00-59)
%m月份(01-12)
%p"上午(am)"或"下午(pm)"
%S秒數(00-59)
%w一星期中的第幾天(0--6等價于星期日--星期六)
%x日期,如09/16/2010
%X時間,如23:48:20
%y兩位數的年份(00-99)
%Y完整的年份(2012)
%%字符'%'

    print(os.date("%Y-%m-%d"))  --輸出2012-04-05
    函數os.clock()返回CPU時間的描述,通常用于計算一段代碼的執行效率。如:

復制代碼
1 local x = os.clock()
2 local s = 0
3 for i = 1, 10000000 do
4 s = s + i
5 end
6 print(string.format("elapsed time: %.2f\n", os.clock() - x))
7
8 --輸出結果為:
9 --elapsed time: 0.21
復制代碼


    2. 其他系統調用:
    函數os.exit()可中止當前程序的執行。函數os.getenv()可獲取一個環境變量的值。如:
    print(os.getenv("PATH"))  --如果環境變量不存在,返回nil。
    os.execute函數用于執行和操作系統相關的命令,如:
    os.execute("mkdir " .. "hello")

posted @ 2014-02-17 17:43 沛沛 閱讀(296) | 評論 (0)編輯 收藏

  I/O庫為文件操作提供了兩種不同的模型,簡單模型和完整模型。簡單模型假設一個當前輸入文件和一個當前輸出文件,他的I/O操作均作用于這些文件。完整模型則使用顯式的文件句柄,并將所有的操作定義為文件句柄上的方法。
    1. 簡單模型:
    I/O庫會將進程標準輸入輸出作為其缺省的輸入文件和輸出文件。我們可以通過io.input(filename)io.output(filename)這兩個函數來改變當前的輸入輸出文件。
    1). io.write函數:
    函數原型為io.write(...)。該函數將所有參數順序的寫入到當前輸出文件中。如:
    io.write("hello","world") --寫出的內容為helloworld

    2). io.read函數:
    下表給出了該函數參數的定義和功能描述:

參數字符串含義
"*all"讀取整個文件
"*line"讀取下一行
"*number"讀取一個數字
<num>讀取一個不超過<num>個字符的字符串

    調用io.read("*all")會讀取當前輸入文件的所有內容,以當前位置作為開始。如果當前位置處于文件的末尾,或者文件為空,那個該調用返回一個空字符串。由于Lua可以高效的處理長字符串,因此在Lua中可以先將數據從文件中完整讀出,之后在通過Lua字符串庫提供的函數進行各種處理。
    調用io.read("*line")會返回當前文件的下一行,但不包含換行符。當到達文件末尾時,該調用返回nil。如:

復制代碼
1 for count = 1,math.huge do
2 local line = io.read("*line") --如果不傳參數,缺省值也是"*line"
3 if line == nil then
4 break
5 end
6 io.write(string.format("%6d ",count),line,"\n")
7 end
復制代碼

    如果只是為了迭代文件中的所有行,可以使用io.lines函數,以迭代器的形式訪問文件中的每一行數據,如:

復制代碼
1 local lines = {}
2 for line in io.lines() do --通過迭代器訪問每一個數據
3 lines[#lines + 1] = line
4 end
5 table.sort(lines) --排序,Lua標準庫的table庫提供的函數。
6 for _,l in ipairs(lines) do
7 io.write(l,"\n")
8 end
復制代碼

    調用io.read("*number")會從當前輸入文件中讀取一個數字。此時read將直接返回一個數字,而不是字符串。"*number"選項會忽略數字前面所有的空格,并且能處理像-3、+5.2這樣的數字格式。如果當前讀取的數據不是合法的數字,read返回nil。在調用read是可以指定多個選項,函數會根據每個選項參數返回相應的內容。如:

復制代碼
 1 --[[
2 6.0 -3.23 1000
3 ... ...
4 下面的代碼讀取注釋中的數字
5 --]]
6 while true do
7 local n1,n2,n3 = io.read("*number","*number","*number")
8 if not n1 then
9 break
10 end
11 print(math.max(n1,n2,n3))
12 end
復制代碼

    調用io.read(<num>)會從輸入文件中最多讀取n個字符,如果讀不到任何字符,返回nil。否則返回讀取到的字符串。如:

復制代碼
1 while true do
2 local block = io.read(2^13)
3 if not block then
4 break
5 end
6 io.write(block)
7 end
復制代碼

    io.read(0)是一種特殊的情況,用于檢查是否到達了文件的末尾。如果沒有到達,返回空字符串,否則nil。

    2. 完整I/O模型:
    Lua中完整I/O模型的使用方式非常類似于C運行時庫的文件操作函數,它們都是基于文件句柄的。
    1). 通過io.open函數打開指定的文件,并且在參數中給出對該文件的打開模式,其中"r"表示讀取,"w"表示覆蓋寫入,即先刪除文件原有的內容,"a"表示追加式寫入,"b"表示以二進制的方式打開文件。在成功打開文件后,該函數將返回表示該文件的句柄,后面所有基于該文件的操作,都需要將該句柄作為參數傳入。如果打開失敗,返回nil。其中錯誤信息由該函數的第二個參數返回,如:
    assert(io.open(filename,mode))  --如果打開失敗,assert將打印第二個參數給出的錯誤信息。
    
    2). 文件讀寫函數read/write。這里需要用到冒號語法,如:

1 local f = assert(io.open(filename,"r"))
2 local t = f:read("*all") --對于read而言,其參數完全等同于簡單模型下read的參數。
3 f:close()

    此外,I/O庫還提供了3個預定義的文件句柄,即io.stdin(標準輸入)、io.stdout(標準輸出)、io.stderr(標準錯誤輸出)。如:
    io.stderr:write("This is an error message.")
    事實上,我們也可以混合使用簡單模式和完整模式,如:

1 local temp = io.input()   --將當前文件句柄保存
2 io.input("newInputfile") --打開新的輸入文件
3 io.input():close() --關閉當前文件
4 io.input(temp) --恢復原來的輸入文件


    3). 性能小技巧:
    由于一次性讀取整個文件比逐行讀取要快一些,但對于較大的文件,這樣并不可行,因此Lua提供了一種折中的方式,即一次讀取指定字節數量的數據,如果當前讀取中的最后一行不是完整的一行,可通過該方式將該行的剩余部分也一并讀入,從而保證本次讀取的數據均為整行數據,以便于上層邏輯的處理。如:
    local lines,rest = f:read(BUFSIZE,"*line") --rest變量包含最后一行中沒有讀取的部分。
    下面是Shell中wc命令的一個簡單實現。

復制代碼
 1 local BUFSIZE = 8192
2 local f = io.input(arg[1]) --打開輸入文件
3 local cc, lc, wc, = 0, 0, 0 --分別計數字符、行和單詞
4 while true do
5 local lines,rest = f:read(BUFSIZE,"*line")
6 if not lines then
7 break
8 end
9 if rest then
10 lines = lines .. rest .. "\n"
11 end
12 cc = cc + #lines
13 --計算單詞數量
14 local _, t = string.gsub(lines."%S+","")
15 wc = wc + t
16 --計算行數
17 _,t = string.gsub(line,"\n","\n")
18 lc = lc + t
19 end
20 print(lc,wc,cc)
復制代碼


    4). 其它文件操作:
    如io.flush函數會將io緩存中的數據刷新到磁盤文件上。io.close函數將關閉當前打開的文件。io.seek函數用于設置或獲取當前文件的讀寫位置,其函數原型為f:seek(whence,offset),如果whence的值為"set",offset的值則表示為相對于文件起始位置的偏移量。如為"cur"(默認值),offset則為相對于當前位置的偏移量,如為"end",則為相對于文件末尾的偏移量。函數的返回值與whence參數無關,總是返回文件的當前位置,即相對于文件起始處的偏移字節數。offset的默認值為0。如:

1 function fsize(file)
2 local current = file:seek() --獲取當前位置
3 local size = file:seek("end") --獲取文件大小
4 file:seek("set",current) --恢復原有的當前位置
5 return size
6 end

    最后需要指出的是,如果發生錯誤,所有這些函數均返回nil和一條錯誤信息。

posted @ 2014-02-17 17:43 沛沛 閱讀(293) | 評論 (0)編輯 收藏

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国产精品第三页| 欧美日韩精品久久久| 国产一级揄自揄精品视频| 亚洲欧美日韩在线| 亚洲欧美一区在线| 韩日视频一区| 亚洲国产婷婷| 欧美黄色小视频| 亚洲一区日韩| 欧美中文字幕在线播放| 亚洲风情亚aⅴ在线发布| 亚洲国产经典视频| 欧美特黄视频| 久久国产一二区| 欧美va日韩va| 欧美中文字幕第一页| 久久尤物视频| 亚洲视频久久| 欧美一区二区在线看| 亚洲精品孕妇| 午夜免费日韩视频| 亚洲精品美女在线| 亚洲综合欧美| 亚洲黄色在线看| 亚洲主播在线| 日韩视频免费观看高清完整版| 一区二区三区蜜桃网| 在线观看国产成人av片| 亚洲免费大片| 伊人久久婷婷色综合98网| 一级成人国产| 影音先锋亚洲一区| 亚洲免费观看视频| 亚洲成色精品| 午夜精品免费视频| 一区二区欧美日韩| 久久五月激情| 久久精品国产在热久久| 欧美日韩大片| 麻豆freexxxx性91精品| 国产精品分类| 亚洲国产精品久久久| 韩国一区二区在线观看| 亚洲影视在线播放| 一本色道88久久加勒比精品| 久久久久久香蕉网| 欧美制服丝袜第一页| 国产精品久久久久aaaa樱花| 亚洲国产精品一区| 亚洲缚视频在线观看| 久久精品国产第一区二区三区最新章节 | 久久国产乱子精品免费女| 亚洲婷婷综合久久一本伊一区| 久久综合久久综合九色| 久久久精品国产一区二区三区| 国产精品福利在线观看网址| 亚洲三级观看| 一区二区三区欧美视频| 欧美电影免费网站| 亚洲黄色成人久久久| 亚洲级视频在线观看免费1级| 久久精品麻豆| 免费在线成人av| 尤物在线精品| 欧美成人午夜免费视在线看片| 欧美v亚洲v综合ⅴ国产v| 在线不卡亚洲| 免费成人av在线看| 亚洲国内精品在线| aa级大片欧美三级| 欧美三级黄美女| 中文欧美在线视频| 久久国产66| 狠狠色综合一区二区| 久久久综合网站| 亚洲欧洲精品一区二区三区| 9人人澡人人爽人人精品| 欧美午夜不卡| 欧美在线视频免费观看| 欧美成人免费大片| 99在线|亚洲一区二区| 国产精品女主播在线观看| 欧美一区二区三区视频免费| 可以免费看不卡的av网站| 亚洲国产欧美一区二区三区同亚洲| 欧美成人精品在线播放| 亚洲精品中文字| 欧美怡红院视频| 精品成人久久| 欧美日韩一区二区欧美激情 | 亚洲视频观看| 国产美女精品一区二区三区| 久久岛国电影| 亚洲精品一区久久久久久| 香蕉乱码成人久久天堂爱免费| 国产欧美日本一区视频| 久久久爽爽爽美女图片| 亚洲国产精品久久久久| 国产乱码精品一区二区三区忘忧草 | 99视频一区二区| 欧美激情亚洲综合一区| 一区二区三区四区五区视频 | 午夜亚洲影视| 国产精品外国| 欧美电影资源| 日韩一级视频免费观看在线| 欧美亚洲免费电影| 亚洲精品五月天| 国产女主播在线一区二区| 久久综合久色欧美综合狠狠 | 亚洲一区二区三区四区五区黄| 嫩草伊人久久精品少妇av杨幂| 亚洲精品欧美在线| 国内精品美女在线观看| 欧美精品三级在线观看| 久久久精品日韩欧美| 女主播福利一区| 欧美一区二区精品| 尤物九九久久国产精品的特点| 国产精品久久久久久久久免费| 一区二区三区 在线观看视| 老牛国产精品一区的观看方式| 国产精品乱码一区二区三区| 欧美国产免费| 欧美一区二区免费| 亚洲美女精品成人在线视频| 欧美成人午夜激情在线| 欧美一区=区| 亚洲在线视频观看| 亚洲精品在线电影| 最近中文字幕mv在线一区二区三区四区 | 日韩一级免费观看| 亚洲国产精品成人精品| 久久青青草原一区二区| 欧美一级大片在线免费观看| 日韩性生活视频| 亚洲精品综合久久中文字幕| 韩国精品在线观看| 狠狠色狠狠色综合人人| 欧美日韩精品免费看| 欧美日韩国产亚洲一区| 欧美日本视频在线| 免费日韩av片| 欧美日本一区二区高清播放视频| 久久久久一区二区三区四区| 久久激情一区| 午夜精品久久久久久| 欧美一区二区三区另类 | 欧美高清在线一区二区| 久久综合国产精品| 免播放器亚洲一区| 久久久在线视频| 欧美成人乱码一区二区三区| 麻豆久久婷婷| 亚洲精品麻豆| 久久精品国产清自在天天线| 久久久久网址| 亚洲成人在线网| 亚洲第一黄网| 日韩午夜中文字幕| 香港久久久电影| 久久久久久尹人网香蕉| 久久久久久久精| 欧美二区在线| 久久一区亚洲| 亚洲人成网站色ww在线| 亚洲一区二区三区免费观看| 亚洲视频999| 久久久九九九九| 美女精品在线观看| 欧美三级韩国三级日本三斤| 国产精品一区二区男女羞羞无遮挡 | 欧美v亚洲v综合ⅴ国产v| 欧美日韩国内自拍| 欧美日韩成人在线观看| 国产日产欧产精品推荐色| 在线看无码的免费网站| 亚洲美女网站| 久久精品国产91精品亚洲| 裸体一区二区| 亚洲精品网址在线观看| 亚洲激情专区| 99国产精品久久久久久久| 亚洲女同在线| 欧美96在线丨欧| 欧美视频第二页| 国产视频一区二区在线观看 | 日韩一区二区电影网| 亚洲视频一区在线观看| 久久激情久久| 欧美午夜精品久久久久久浪潮| 欧美日韩在线三区| 亚洲日本在线观看| 久久精品国产久精国产一老狼| 亚洲国产精品久久久久久女王 | 性视频1819p久久| 亚洲精品国精品久久99热一| 亚洲另类在线视频| 欧美/亚洲一区| 精品999在线播放|