C API — 테이블·레지스트리·전역 함수
C API — 테이블·레지스트리·전역 함수 (The Application Program Interface — Table, Registry, and Global Functions)
이 절은 루아 C API에서 테이블, 레지스트리, 전역에 접근하는 함수들을 정리해요. 기본 개념은 "[레지스트리 (Registry)]"와 "[응용 프로그램 인터페이스]" 절에 있어요.
테이블 생성
void lua_createtable (lua_State *L, int narr, int nrec)— 배열 슬롯narr개, 레코드 슬롯nrec개를 미리 예약한 새 빈 테이블을 만들어 push해요.void lua_newtable (lua_State *L)—lua_createtable(L, 0, 0)과 같은 새 빈 테이블 push.
테이블/레지스트리/전역 읽기 (Get)
int lua_gettable(L, int idx)—idx의 테이블에서 맨 위 값을 키로 조회해서 결과를 push해요.__index메타메서드를 존중해요.int lua_getfield(L, int idx, const char *k)— 테이블의 문자열 필드k를 조회해 push.int lua_geti(L, int idx, lua_Integer n)— 테이블의 정수 인덱스n을 조회해 push.int lua_getglobal(L, const char *name)— 전역name을 조회해 push.int lua_getmetatable(L, int idx)—idx값의 메타테이블을 push (있으면 1, 없으면 0).int lua_getuservalue(L, int idx, int n)— userdata의 n번째 사용자 값을 push (5.4).int lua_rawget(L, int idx)— 메타메서드 없이 원시 테이블 읽기.int lua_rawgeti(L, int idx, lua_Integer n)— 원시 정수 인덱스 읽기.int lua_rawgetp(L, int idx, const void *p)— 원시 lightuserdata 키로 읽기.int lua_next(L, int idx)— 테이블 순회 (키는 pop, 다음 쌍을 push).size_t lua_rawlen(L, int idx)— 값의 원시 길이.
테이블/레지스트리/전역 쓰기 (Set)
void lua_settable(L, int idx)— 맨 위 두 값을 (키, 값)으로idx테이블에 저장.__newindex존중.void lua_setfield(L, int idx, const char *k)— 문자열 키k에 값을 저장.void lua_seti(L, int idx, lua_Integer n)— 정수 인덱스에 저장.void lua_setglobal(L, const char *name)— 전역name에 맨 위 값을 저장.int lua_setmetatable(L, int idx)— 맨 위 값을idx값의 메타테이블로 설정.int lua_setuservalue(L, int idx, int n)— userdata의 사용자 값 설정.void lua_rawset(L, int idx)— 원시 테이블 쓰기 (메타메서드 무시).void lua_rawseti(L, int idx, lua_Integer n)— 원시 정수 인덱스 쓰기.void lua_rawsetp(L, int idx, const void *p)— 원시 lightuserdata 키로 쓰기.void lua_closeslot(L, int idx)— 위치idx의 to-be-closed 변수를 닫기 (5.4).
레지스트리와 참조
LUA_REGISTRYINDEX는 레지스트리(전역 테이블)의 가상 인덱스예요. C 코드가 루아 값을 보관하는 공간이에요.
int lua_getfield(L, LUA_REGISTRYINDEX, key)— 레지스트리 필드 조회.void lua_setfield(L, LUA_REGISTRYINDEX, key)— 레지스트리 필드 저장.- 보조 라이브러리의
luaL_ref(L, t)/luaL_unref(L, t, ref)가 참조 번호 관리에 쓰여요.
이름-기반 접근의 공통 패턴:
int lua_getglobal(lua_State *L, const char *name);
int lua_setglobal(lua_State *L, const char *name);
이들은 사실 전역 테이블(레지스트리의 LUA_RIDX_GLOBALS 필드)에 대한 lua_getfield/lua_setfield로 구현된 편의 함수예요.
공통 사용 예시
/* 전역 테이블 t에서 t.birhtday = 42 설정 */
lua_getglobal(L, "t"); /* 전역 t push */
lua_pushliteral(L, "value"); /* 키 */
lua_pushinteger(L, 42); /* 값 */
lua_settable(L, -3); /* t["value"] = 42 */
lua_pop(L, 1); /* t 제거 */
/* 레지스트리에 값 보관 */
lua_pushinteger(L, 123);
lua_setfield(L, LUA_REGISTRYINDEX, "my_int");
순회 (Iteration)
lua_next로 테이블을 순회해요. 첫 호출 전에 nil 키를 push하고, 반환으로 키와 값을 얻어요. lua_next가 1을 반환하면 더 순회가 가능하고, 0이면 끝이에요.
lua_pushnil(L); /* 첫 키 */
while (lua_next(L, -2) != 0) {
/* 키는 -2, 값은 -1 */
const char *key = lua_tostring(L, -2);
lua_pop(L, 1); /* 값 제거, 키를 맨 위로 */
}
스택 관리 예시
/* 스택 맨 위: 테이블이 있다고 가정 */
lua_pushliteral(L, "name");
lua_rawget(L, -2); /* t["name"]를 원시로 가져옴 */
const char *name = lua_tostring(L, -1);
lua_pop(L, 1);
출처: C API — 테이블·레지스트리·전역 함수 (The Application Program Interface — Table, Registry, and Global Functions)
본문
레지스트리 주의
레지스트리는 C에서만 직접 접근하는 게 관례예요. 루아 스크립트가 레지스트리에 직접 쓰면 상태가 오염될 수 있어요. C 코드가 상태 전역으로 값을 보관할 때만 사용해요.
__index/__newindex 존중 vs 원시 접근
lua_gettable/lua_settable은 메타메서드(__index, __newindex)를 존중하지만, lua_rawget/lua_rawset는 존중하지 않아요. 테이블을 "원시적으로" 다뤄야 할 때(예: 내장 테이블 조작) 원시 버전을 사용해요.