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는 존중하지 않아요. 테이블을 "원시적으로" 다뤄야 할 때(예: 내장 테이블 조작) 원시 버전을 사용해요.

더 알아보기