사용자 도구

사이트 도구


kb:luaapistack

LuaApi/Stack

스택 다루기

lua_push...

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);

push 시리즈 함수들은 딱히 특별할 것이 없다. 그냥 스택에다 해당하는 타입의 아이템을 푸쉬한다. 루아에서는 문자열이 0으로 끝나야만 하는 것이 아니기 때문에 – 어떤 바이너리 값도 될 수 있다 – lua_pushlstring 함수가 존재한다. 일반적인 C 문자열인 경우에는 그냥 lua_pushstring 함수를 사용하면 된다.

lua_pushcclosure

void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);

C 함수에다 upvalue를 할당해서 closure를 만들기 위해 사용하는 함수다. upvalue나 closure에 관한 것은 LuaGlossary 페이지를 참고하기 바란다. fn은 C 함수에 대한 포인터이고, n은 upvalue의 갯수다. 이 함수를 호출하기 전에 upvalue로 사용할 아이템들을 스택에다 n개만큼 푸쉬해둬야 한다. lua_pushcclosure 호출 후에는 푸쉬했던 아이템들이 모두 팝되고, 생성된 closure가 스택의 맨 위에 푸쉬된다.

호출 전의 스택                       호출 후의 스택 
+---------+                          +---------+ 
| upvalue |                          | closure |  
+---------+                          +---------+ 
| upvalue |                          |   ...   | 
+---------+                          +---------+ 
|   ...   |                          |   ...   | 
+---------+                          +---------+ 

임의의 C 함수를 1개의 int형 upvalue와 함께 등록하기 위해서는 다음과 같이 하면 된다.

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개 푸쉬되었으므로...
}

위의 예제에서 counter 함수가 upvalue를 사용하는 함수라는 것을 알 수 있다. upvalue를 액세스하기 위해서는 lua_upvalueindex 함수를 사용한다.

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;
}

lua_pushfstring

const char* lua_pushfstring(lua_State *L, const char *fmt, ...);

sprintf 함수와 같이 포맷과 인수들을 받아들여, 문자열을 생성한 다음, 그 문자열을 스택에다 푸쉬하고, 그 문자열의 포인터를 반환한다. sprintf 처럼 다양한 포맷을 지원하지는 않으며, 현재 지원하는 포맷은 %%('%' 문자를 위해), %s(문자열), %d(정수), %f(더블), %c(캐릭터) 정도이다.

lua_concat

void lua_concat (lua_State *L, int n);

스택에서 n개만큼의 아이템을 팝해서, 그것을 모두 문자열로 변환해 합친 다음, 푸쉬한다. 숫자 같은 경우에는 자동으로 문자열로 변환하고, 다른 타입 같은 경우, 문자열로 변환하기 위해 메타 메서드를 호출하기도 한다.

lua_concat(L, 2);

호출 전의 스택                       호출 후의 스택 
+----------+                          
| "world"  |                          
+----------+                          +---------------+ 
| "hello " |                          | "hello world" | 
+----------+                          +---------------+ 
|   ...    |                          |     ...       |
+----------+                          +---------------+

lua_type

int lua_type(lua_State *L, int index);

지정된 위치의 스택에 있는 아이템의 종류를 반환한다. 반환하는 종류는 lua.h에 나와있다. LUA_TNIL, LUA_TBOOLEAN, LUA_TNUMBER, LUA_TSTRING, LUA_TTABLE, LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD 정도다.

lua_is...

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);

지정된 위치의 스택에 있는 아이템이 해당하는 타입으로 '변환될 수 있는 값인가'를 반환하는 함수들이다. 즉 숫자들의 경우, lua_isnumber 함수를 만족할 뿐만 아니라, lua_isstring 함수 역시 만족한다. 실제 타입을 알아내기 위해서는 lua_type 함수를 사용해야 한다.

lua_to...

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);

지정된 위치의 스택에 있는 아이템을 해당하는 타입으로 변환해서 반환한다. 지정된 인덱스의 아이템이 해당 타입으로 변환이 불가능한 타입이거나, 인덱스 자체가 잘못된 경우 모두 0 또는 NULL을 반환한다.

lua_tostring 함수의 경우, 반환한 문자열 아이템이 스택에서 팝되는 경우, 가비지 컬렉션에 의해 언제 사라질 지 알 수 없다. 그러므로 문자열을 계속 보관하기를 원한다면 복사를 해두어야 한다. 루아에서 문자열은 반드시 0으로 끝나는 것이 아니기 때문에, 복사를 할 때, 먼저 lua_strlen 함수를 이용해 길이를 조사해야 한다.

lua_gettop

int lua_gettop (lua_State *L);

스택에 들어있는 아이템들의 갯수를 반환한다. 즉 이 함수가 반환하는 값은 가장 최근에 푸쉬된 아이템의 스택 인덱스와 같다.

lua_settop

void lua_settop (lua_State *L, int index);

스택의 탑을 설정한다. 만일 10개의 아이템들이 스택에 들어있는데, index 값을 7로 줘서 이 함수를 호출하면, 7개의 아이템들만이 남고, 나머지 3개는 스택의 맨 위에서부터 버려진다. 반대의 경우, 즉 7개가 있는데 10을 index로 준 경우, nil 값이 모자란 갯수만큼 푸쉬된다. 사실 lua_pop 매크로가 이 함수를 이용한다.

#define lua_pop(L,n) lua_settop(L, -(n)-1);

lua_pushvalue

void lua_pushvalue (lua_State *L, int index);

해당하는 위치에 있는 아이템을 복사해서 스택의 맨 위에다 푸쉬한다.

lua_pushvalue(L, -1);

호출 전의 스택                       호출 후의 스택 
                                     +---------+ 
                                     |   999   |  
+---------+                          +---------+
|   999   |                          |   999   | 
+---------+                          +---------+ 
|   888   |                          |   888   | 
+---------+                          +---------+ 
|   ...   |                          |   ...   |
+---------+                          +---------+

lua_remove

void lua_remove (lua_State *L, int index);

해당하는 위치에 있는 아이템을 스택에서 제거한다. index 위치보다 위에 있던 아이템들은 하나씩 내려온다.

lua_remove(L, -2);

호출 전의 스택                       호출 후의 스택 
+---------+                          
|   999   |                          
+---------+                          +---------+ 
|   888   |                          |   999   | 
+---------+                          +---------+ 
|   777   |                          |   777   |
+---------+                          +---------+
|   ...   |                          |   ...   |
+---------+                          +---------+         

lua_insert

void lua_insert (lua_State *L, int index);

스택의 맨 위에 있는 아이템을 지정된 위치로 옮긴다. index 위치보다 위에 있던 아이템들은 하나씩 올라간다.

lua_insert(L, -2);

호출 전의 스택                       호출 후의 스택 
+---------+                          +---------+ 
|   999   |                          |   888   | 
+---------+                          +---------+ 
|   888   |                          |   999   |
+---------+                          +---------+
|   777   |                          |   777   |
+---------+                          +---------+         

lua_replace

void lua_replace (lua_State *L, int index);

스택의 맨 위에 있는 아이템을 팝해서 지정된 위치에 있는 값으로 설정한다. 아이템의 이동은 없다.

lua_replace(L, -3);

호출 전의 스택                       호출 후의 스택 
+---------+                          
|   999   |                           
+---------+                          +---------+ 
|   888   |                          |   888   |
+---------+                          +---------+
|   777   |                          |   999   |
+---------+                          +---------+         

lua_checkstack

int lua_checkstack (lua_State *L, int extra);

루아의 스택 크기를 늘릴 때 사용하는 함수다. 루아에서 C 함수를 호출하는 경우, 루아는 스택에 적어도 20개의 자리를 확보해준다. 즉 C 쪽에서 20개까지 아이템을 푸쉬할 수 있다는 말이다. 일반적인 경우 이걸로 충분하다. 그러나 이 크기를 늘려야 할 때도 있을 것이다.

이 함수를 호출하면, 현재 스택에다가 extra 갯수만큼의 빈 자리를 추가한다. 참고로 extra 인수의 값을 음수로 줘서 스택의 크기를 줄이는 것은 불가능하다. 무시된다.

성공적으로 스택의 크기를 늘린 경우에는 1을 반환하고, 스택의 크기를 더 이상 늘릴 수 없는 경우에는 0을 반환한다. 참고로 스택의 최대 크기는 LUA_MAXCSTACK 값으로서 llimits.h 파일에 정의되어 있다. 기본값은 2048이다.


kb/luaapistack.txt · 마지막으로 수정됨: 2014/11/07 10:02 (바깥 편집)