프로그래밍

[Lua] Lua랑 C/C++ 사이 통신하는 방법

푸불 2022. 2. 12. 19:05

 

신조차 모독하는 사상 최대의 인터프리터 luajit

루아51이든 루아지트든 똑같다고는하는데

C++에 임베딩한 후에 뭘 해야할지 잘 모르겠었다

 

근데 어쩌다보니 땔질좀 하니 뭔가 되긴 하더라

그 내용을 정리해보도록 하겠다

진짜 기본 시작 세팅은 건너뛰었는데,

이부분은 나중에 글 쓸수도 있고 아닐수도 있습니다

 

기본 작동원리

꽤 중요한 대목이다

전공자라면 수업시간에 함수의 인수는 스택에 쌓인다는걸 배웠을 것이다

루아도 비슷한 느낌으로 스택을 사용한다

C++ 코드로, 루아에 변수를 할당하고싶다고 쳐보자.

그럼 lua_push로 시작하는 함수들을 이용해서 C++에서 계산한 값을 스택에 넣어주고,

lua_setglobal같은 함수를 이용해서 스택에서 빼서 lua에 할당해준다.

 

예를들어보자

lua_pushnumber(L,5); // 5를 스택에 넣는다

lua_setglobal(L,"N"); // 스택에서 아까 넣은 5를 빼서 N을 할당한다.

 

만약 이렇게 한다음, lua에서 print(N)을 하면 5가 나온다. 참 쉽죠? 

이번엔 앞과 반대로, Lua의 값을 C++로 가져오고싶다.

이 경우엔 반대로 Lua의 변수를 공용 스택에 쌓고,

공용 스택에서 C++이 값을 꺼내오는 방식으로 구현하면 된다.

 

마찬가지로 예를 들어보자.

lua_getglobal(L,"N"); // lua의 전역변수 N을 읽어서 스택에 쌓는다

int a = lua_tonumber(L, 1); // 스택에서 변수를 빼어 수로 변환한다

이런 코드를 호출하면 a는 N값이 될 것이다.

 

위에 있는 것으로 일단 어떻게 Lua랑 C++가 통신하는지는 알았다.

이제는 좀더 디테일한 부분을 짚어보자.

 

다른 자료형은?

위에서는 number 값만 왔다갔다하는걸 봤다.

그런데 lua는 number말고도 table같은 자료형이 있다.

lua로 여러가지를 하고싶을 것이다.

단순 수치가 아니라 좀더 복잡한 구조체를 lua에 넘겨주고 싶을수 있고,

lua에서 특정 함수를 호출하고 싶을수도 있다.

 

근데 큰 원리는 비슷하다. 진짜 약간만 바뀐다.

 

1. table을 lua에 넘겨보자!

lua_newtable이라는 함수가 있다.

우리는 이런식으로 스택에 빈테이블을 때려박을수 있다

당연히 이 직후엔 스택에 있는 table이 비어있다.

키값을 push해준다음, 값을 push해준다.

(lua에서 table의 값으로 집어넣을 수 있는 것을 push해주면 된다. 여기선 number)

lua_settable를 이용해서 아까 만든 스택상의 table에 키-값 쌍을 넣어줄 수 있다.

이때 참조하는 키-값은 스택 맨 위에 두개값을 순서대로 가져온다. 

이제 아까와 마찬가지로 lua_setglobal을 이용해 값을 lua의 변수로 할당해주면 된다.

        lua_newtable(L);
        lua_pushstring(L, "line");
        lua_pushnumber(L, 5);
        lua_settable(L, 1); // 1은 인덱스값, 스택상의 위치를 의미함
        lua_setglobal(L, "note");

 

이런 느낌이다

 

 

2.C에서 lua 함수를 호출해서 값을 받아보자

대략 이런 함수가 lua에 적혀있다고 치자

우리는 이 함수를 호출해서 가져와야한다

일단 스택에 lua의 test 함수를 넣어야한다

그다음 test에 넘겨줄 매개변수를 푸쉬해주고...

이 test 함수를 호출해준다. 그러면 스택 맨위에 test의 리턴값이 담긴다.

이제 이 값을 스택에서 빼서 처리해주면 된다.

 

이렇게 하면 Lua의 함수를 C++이 사용하고, 그 결과값을 받을 수 있는 것이다.

 

이를 코드로 나타내면 아래와 같다.

lua_getglobal로 루아의 test함수를 스택에 얹는다.

그다음, test에 넘겨줄 인자를 스택에 push해준다. (여기선 number)

그 후 lua_call 해주면, lua의 test 함수를 실행한다.

그 결과물을 lua는 다시 공용 스택 맨 위에다가 얹어놓는다.

즉, lua_call을 하고나면 공용 스택 맨 위에 반환값이 올라온단 얘기다.

이거를 lua_tonumber로 빼서, 우리는 lua의 함수를 실행해서 그 반환값을 가져올 수 있게 된다.

 

마치며

이쯤되면 눈치챘겠지만,

루아와 C++을 연동하는 과정은 위에서 설명한 공용 스택 공간에 적당히 데이터를 쌓은후,

C++에서 알맞은 lua_뭐시기 함수를 호출해서 적절히 처리해주는 방식으로 이루어진다

 

레퍼런스 매뉴얼에 API에 대한 설명이 나와있으니 확인해보면 좋다.

https://www.lua.org/manual/5.4/manual.html#lua_setglobal

 

 

 

 

2022/2/24 수정:

lua_tonumber는 호출한다고 스택에서 pop하지 않는다

그림에선 잘못 나타냈는데 lua_pop을 따로 해줘야지 number element가 스택에서 제거된다