사용자 도구

사이트 도구


kb:luaapistack

차이

문서의 선택한 두 판 사이의 차이를 보여줍니다.

차이 보기로 링크

kb:luaapistack [2014/11/07 10:02] (현재)
줄 1: 줄 1:
 +====== LuaApi/​Stack ======
 +스택 다루기
 +
 +===== lua_push... =====
 +<code cpp>
 +void lua_pushboolean ​      ​(lua_State *L, int b);
 +void lua_pushnumber ​       (lua_State *L, lua_Number n);
 +void lua_pushlstring ​      ​(lua_State *L, const char *s, size_t len);
 +void lua_pushstring ​       (lua_State *L, const char *s);
 +void lua_pushnil ​          ​(lua_State *L);
 +void lua_pushcfunction ​    ​(lua_State *L, lua_CFunction f);
 +void lua_pushlightuserdata (lua_State *L, void *p);
 +</​code>​
 +push 시리즈 함수들은 딱히 특별할 것이 없다. 그냥 스택에다 해당하는 타입의 아이템을 푸쉬한다. 루아에서는 문자열이 0으로 끝나야만 하는 것이 아니기 때문에 -- 어떤 바이너리 값도 될 수 있다 -- lua_pushlstring 함수가 존재한다. 일반적인 C 문자열인 경우에는 그냥 lua_pushstring 함수를 사용하면 된다.
 +
 +
 +===== lua_pushcclosure =====
 +<code cpp>
 +void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
 +</​code>​
 +C 함수에다 upvalue를 할당해서 closure를 만들기 위해 사용하는 함수다. upvalue나 closure에 관한 것은 LuaGlossary 페이지를 참고하기 바란다. fn은 C 함수에 대한 포인터이고,​ n은 upvalue의 갯수다. 이 함수를 호출하기 전에 upvalue로 사용할 아이템들을 스택에다 n개만큼 푸쉬해둬야 한다. lua_pushcclosure 호출 후에는 푸쉬했던 아이템들이 모두 팝되고, 생성된 closure가 스택의 맨 위에 푸쉬된다.
 +<​code>​
 +호출 전의 스택 ​                      ​호출 후의 스택 ​
 ++---------+ ​                         +---------+ ​
 +| upvalue |                          | closure |  ​
 ++---------+ ​                         +---------+ ​
 +| upvalue |                          |   ​... ​  ​| ​
 ++---------+ ​                         +---------+ ​
 +|   ​... ​  ​| ​                         |   ​... ​  ​| ​
 ++---------+ ​                         +---------+ ​
 +</​code>​
 +임의의 C 함수를 1개의 int형 upvalue와 함께 등록하기 위해서는 다음과 같이 하면 된다.
 +<code cpp>
 +static int counter(lua_State* L); // 어딘가에 선언되어 있는 C 함수
 +
 +...
 +
 +int create_closure(lua_State* L)
 +{
 +    lua_pushnumber(L,​ (double)997); ​  // upvalue로 사용할 값을 스택에다 푸쉬
 +    lua_pushcclosure(L,​ &​counter,​ 3); // closure 생성
 +    return 1;                         // 스택의 맨 위에 closure가 1개 푸쉬되었으므로...
 +}
 +</​code>​
 +위의 예제에서 counter 함수가 upvalue를 사용하는 함수라는 것을 알 수 있다. upvalue를 액세스하기 위해서는 lua_upvalueindex 함수를 사용한다.
 +<code cpp>
 +static int counter(lua_State* L)
 +{
 +    int val = (int)lua_tonumber(L,​ lua_upvalueindex(1));​ // upvalue를 읽어온다.
 +    lua_pushnumber(L,​ ++val); ​                           // 증가시킨 값을 푸쉬한다.
 +    lua_pushvalue(L,​ -1);                                // 방금 푸쉬한 값을 복사해서 다시 푸쉬한다.
 +    lua_replace(L,​ lua_upvalueindex(1)); ​                // 복사해서 푸쉬한 값으로 upvalue를 치환한다.
 +    return 1;
 +}
 +</​code>​
 + 
 +
 +===== lua_pushfstring =====
 +<code cpp>
 +const char* lua_pushfstring(lua_State *L, const char *fmt, ...);
 +</​code>​
 + ​sprintf 함수와 같이 포맷과 인수들을 받아들여,​ 문자열을 생성한 다음, 그 문자열을 스택에다 푸쉬하고,​ 그 문자열의 포인터를 반환한다. sprintf 처럼 다양한 포맷을 지원하지는 않으며, 현재 지원하는 포맷은 %%('​%'​ 문자를 위해), %s(문자열),​ %d(정수), %f(더블), %c(캐릭터) 정도이다.
 +
 +
 +===== lua_concat =====
 +<code cpp>
 +void lua_concat (lua_State *L, int n);
 +</​code>​
 +스택에서 n개만큼의 아이템을 팝해서, 그것을 모두 문자열로 변환해 합친 다음, 푸쉬한다. 숫자 같은 경우에는 자동으로 문자열로 변환하고,​ 다른 타입 같은 경우, 문자열로 변환하기 위해 메타 메서드를 호출하기도 한다.
 +<​code>​
 +lua_concat(L,​ 2);
 +
 +호출 전의 스택 ​                      ​호출 후의 스택 ​
 ++----------+ ​                         ​
 +| "​world" ​ |                          ​
 ++----------+ ​                         +---------------+ ​
 +| "hello " |                          | "hello world" | 
 ++----------+ ​                         +---------------+ ​
 +|   ​... ​   |                          |     ​... ​      |
 ++----------+ ​                         +---------------+
 +</​code>​
 +
 +
 +===== lua_type =====
 +<code cpp>
 +int lua_type(lua_State *L, int index);
 +</​code>​
 +지정된 위치의 스택에 있는 아이템의 종류를 반환한다. 반환하는 종류는 lua.h에 나와있다. LUA_TNIL, LUA_TBOOLEAN,​ LUA_TNUMBER,​ LUA_TSTRING,​ LUA_TTABLE, LUA_TFUNCTION,​ LUA_TUSERDATA,​ LUA_TTHREAD 정도다.
 +
 +
 +===== lua_is... =====
 +<code cpp>
 +int lua_isnil ​          ​(lua_State *L, int index);
 +int lua_isboolean ​      ​(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_isfunction ​     (lua_State *L, int index);
 +int lua_iscfunction ​    ​(lua_State *L, int index);
 +int lua_isuserdata ​     (lua_State *L, int index);
 +int lua_islightuserdata (lua_State *L, int index);
 +</​code>​
 +지정된 위치의 스택에 있는 아이템이 해당하는 타입으로 '''​변환될 수 있는 값인가'''​를 반환하는 함수들이다. 즉 숫자들의 경우, lua_isnumber 함수를 만족할 뿐만 아니라, lua_isstring 함수 역시 만족한다. 실제 타입을 알아내기 위해서는 lua_type 함수를 사용해야 한다.
 +
 +
 +===== lua_to... =====
 +<code cpp>
 +int            lua_toboolean ​  ​(lua_State *L, int index);
 +lua_Number ​    ​lua_tonumber ​   (lua_State *L, int index);
 +const char    *lua_tostring ​   (lua_State *L, int index);
 +size_t ​        ​lua_strlen ​     (lua_State *L, int index);
 +lua_CFunction ​ lua_tocfunction (lua_State *L, int index);
 +void          *lua_touserdata ​ (lua_State *L, int index);
 +lua_State ​    ​*lua_tothread ​   (lua_State *L, int index);
 +void          *lua_topointer ​  ​(lua_State *L, int index);
 +</​code>​
 +지정된 위치의 스택에 있는 아이템을 해당하는 타입으로 변환해서 반환한다. 지정된 인덱스의 아이템이 해당 타입으로 변환이 불가능한 타입이거나,​ 인덱스 자체가 잘못된 경우 모두 0 또는 NULL을 반환한다.
 +
 +lua_tostring 함수의 경우, 반환한 문자열 아이템이 스택에서 팝되는 경우, 가비지 컬렉션에 의해 언제 사라질 지 알 수 없다. 그러므로 문자열을 계속 보관하기를 원한다면 복사를 해두어야 한다. 루아에서 문자열은 반드시 0으로 끝나는 것이 아니기 때문에, 복사를 할 때, 먼저 lua_strlen 함수를 이용해 길이를 조사해야 한다.
 +
 +
 +===== lua_gettop =====
 +<code cpp>
 +int lua_gettop (lua_State *L);
 +</​code>​
 +스택에 들어있는 아이템들의 갯수를 반환한다. 즉 이 함수가 반환하는 값은 가장 최근에 푸쉬된 아이템의 스택 인덱스와 같다.
 +
 +
 +===== lua_settop =====
 +<code cpp>
 +void lua_settop (lua_State *L, int index);
 +</​code>​
 +스택의 탑을 설정한다. 만일 10개의 아이템들이 스택에 들어있는데,​ index 값을 7로 줘서 이 함수를 호출하면,​ 7개의 아이템들만이 남고, 나머지 3개는 스택의 맨 위에서부터 버려진다. 반대의 경우, 즉 7개가 있는데 10을 index로 준 경우, nil 값이 모자란 갯수만큼 푸쉬된다. 사실 lua_pop 매크로가 이 함수를 이용한다.
 +<code cpp>
 +#define lua_pop(L,​n) lua_settop(L,​ -(n)-1);
 +</​code>​
 +
 +
 +===== lua_pushvalue =====
 +<code cpp>
 +void lua_pushvalue (lua_State *L, int index);
 +</​code>​
 +해당하는 위치에 있는 아이템을 복사해서 스택의 맨 위에다 푸쉬한다.
 +<​code>​
 +lua_pushvalue(L,​ -1);
 +
 +호출 전의 스택 ​                      ​호출 후의 스택 ​
 +                                     ​+---------+ ​
 +                                     ​| ​  ​999 ​  ​|  ​
 ++---------+ ​                         +---------+
 +|   ​999 ​  ​| ​                         |   ​999 ​  ​| ​
 ++---------+ ​                         +---------+ ​
 +|   ​888 ​  ​| ​                         |   ​888 ​  ​| ​
 ++---------+ ​                         +---------+ ​
 +|   ​... ​  ​| ​                         |   ​... ​  |
 ++---------+ ​                         +---------+
 +</​code>​
 +
 +
 +===== lua_remove =====
 +<code cpp>
 +void lua_remove (lua_State *L, int index);
 +</​code>​
 +해당하는 위치에 있는 아이템을 스택에서 제거한다. index 위치보다 위에 있던 아이템들은 하나씩 내려온다.
 +<​code>​
 +lua_remove(L,​ -2);
 +
 +호출 전의 스택 ​                      ​호출 후의 스택 ​
 ++---------+ ​                         ​
 +|   ​999 ​  ​| ​                         ​
 ++---------+ ​                         +---------+ ​
 +|   ​888 ​  ​| ​                         |   ​999 ​  ​| ​
 ++---------+ ​                         +---------+ ​
 +|   ​777 ​  ​| ​                         |   ​777 ​  |
 ++---------+ ​                         +---------+
 +|   ​... ​  ​| ​                         |   ​... ​  |
 ++---------+ ​                         +---------+ ​        
 +</​code>​
 +
 +===== lua_insert =====
 +<code cpp>
 +void lua_insert (lua_State *L, int index);
 +</​code>​
 +스택의 맨 위에 있는 아이템을 지정된 위치로 옮긴다. index 위치보다 위에 있던 아이템들은 하나씩 올라간다.
 +<​code>​
 +lua_insert(L,​ -2);
 +
 +호출 전의 스택 ​                      ​호출 후의 스택 ​
 ++---------+ ​                         +---------+ ​
 +|   ​999 ​  ​| ​                         |   ​888 ​  ​| ​
 ++---------+ ​                         +---------+ ​
 +|   ​888 ​  ​| ​                         |   ​999 ​  |
 ++---------+ ​                         +---------+
 +|   ​777 ​  ​| ​                         |   ​777 ​  |
 ++---------+ ​                         +---------+ ​        
 +</​code>​
 +
 +
 +===== lua_replace =====
 +<code cpp>
 +void lua_replace (lua_State *L, int index);
 +</​code>​
 +스택의 맨 위에 있는 아이템을 팝해서 지정된 위치에 있는 값으로 설정한다. 아이템의 이동은 없다.
 +<​code>​
 +lua_replace(L,​ -3);
 +
 +호출 전의 스택 ​                      ​호출 후의 스택 ​
 ++---------+ ​                         ​
 +|   ​999 ​  ​| ​                          
 ++---------+ ​                         +---------+ ​
 +|   ​888 ​  ​| ​                         |   ​888 ​  |
 ++---------+ ​                         +---------+
 +|   ​777 ​  ​| ​                         |   ​999 ​  |
 ++---------+ ​                         +---------+ ​        
 +</​code>​
 +
 +
 +===== lua_checkstack =====
 +<code cpp>
 +int lua_checkstack (lua_State *L, int extra);
 +</​code>​
 +루아의 스택 크기를 늘릴 때 사용하는 함수다. 루아에서 C 함수를 호출하는 경우, 루아는 스택에 적어도 20개의 자리를 확보해준다. 즉 C 쪽에서 20개까지 아이템을 푸쉬할 수 있다는 말이다. 일반적인 경우 이걸로 충분하다. 그러나 이 크기를 늘려야 할 때도 있을 것이다. ​
 +
 +이 함수를 호출하면,​ 현재 스택에다가 extra 갯수만큼의 빈 자리를 추가한다. 참고로 extra 인수의 값을 음수로 줘서 스택의 크기를 줄이는 것은 불가능하다. 무시된다.
 +
 +성공적으로 스택의 크기를 늘린 경우에는 1을 반환하고,​ 스택의 크기를 더 이상 늘릴 수 없는 경우에는 0을 반환한다. 참고로 스택의 최대 크기는 LUA_MAXCSTACK 값으로서 llimits.h 파일에 정의되어 있다. 기본값은 2048이다.
 +
 +----
 +  * see also [[LuaApi]]
  
kb/luaapistack.txt · 마지막으로 수정됨: 2014/11/07 10:02 (바깥 편집)