다른 사고방식 으로 c 호출 lua 함수 실현

줄곧 이 문 제 를 해결 하려 고 했 는데, 최근 에 좀 한가 한 김 에 이 작은 모듈 을 완성 하 였 다.
가장 간단 한 c 리 셋 lua 함수 에 대해 모두 가 비교적 잘 알 고 있 을 것 입 니 다. lua 의 전체 함수 호출 에 대해 luagetglobal 과 luacall 하면 됩 니 다. 그러나 이것 은 숙주 프로그램 에 죽은 lua 의 함수 이름 을 써 야 합 니 다. 결합 성 이 너무 강 합 니 다. 저 는 예전 에 실 현 된 이벤트 알림 방식 에 문제 가 있어 서 다른 방법 으로 실현 하고 싶 습 니 다.
그 후에 저 는 또 다른 방식, 즉 함수 명 등록 방식 을 사 용 했 습 니 다. lua 에 함 수 를 썼 고 이 함수 명 을 숙주 에 게 등 록 했 습 니 다. 숙주 는 특정한 조건 에서 이 함수 이름 의 함 수 를 호출 했 습 니 다.이러한 방식 은 결합 성 문 제 를 해결 하 였 으 나 사용 이 불편 하고 들 어 오 는 매개 변수 가 너무 많 으 며 문자열 의 일치 호출 은 약간의 성능 손실 이 있 습 니 다.
나중에 cocos2dx 에서 함수 인용 을 사용 하여 lua 의 함 수 를 호출 한 것 같 아서 정말 좋 은 방법 이 었 다.숙주 프로그램 은 특정 이벤트 에 등 록 된 모든 함 수 를 호출 하면 lua 함수 호출 을 완성 할 수 있 습 니 다. 결합 성 이 매우 작 기 때문에 디지털 참조 방식 으로 lua 함 수 를 호출 하 는 간단 한 방법 을 실현 하 였 습 니 다.
핵심 사상 은 lua 가 제공 하 는 레 지 스 트 에 table 을 추가 하 는 것 입 니 다. 이 table 의 key 는 이른바 lua 함수 이기 때문에 value 는 lua 함수 의 값 입 니 다. lua 함 수 를 호출 할 때마다 ref 에 따라 function 을 직접 찾 을 수 있 습 니 다. 그러면 이 lua 함 수 를 직접 호출 할 수 있 습 니 다.
다음은 한 걸음 한 걸음.우선 전체 레 지 스 트 에 table 을 등록 해 야 합 니 다.cocos2dx 에서 string 을 사용 하여 key 를 만 들 었 습 니 다. 여기 서 저 는 구름 바람 이 큰 신의 글 에 따라 lightuserdata 를 key 로 사 용 했 습 니 다. 그러면 key 의 색인 시간 이 조금 줄 어 들 것 입 니 다. number 를 key 로 사용 할 수 없다 는 것 을 기억 하 세 요. 이것 은 lua 에 의 해 보존 되 었 습 니 다.
//////////////////////////////////////////////////////////////////////////
//	static light userdata key
static int s_nLuaFunctionRefKey = 0;
void* GetLuaFunctionRefKey()
{
	return (void*)&s_nLuaFunctionRefKey;
}

//	static lua function reference id
static int s_nLuaFunctionRefId = 0;
int GetLuaFunctionRefId()
{
	return ++s_nLuaFunctionRefId;
}

여기 서 우 리 는 정적 변수의 주 소 를 key 로 사용 하고 int 를 ref 의 색인 생 성기 로 사용 합 니 다.
ref 와 func 를 기록 하기 위해 table 을 만 들 었 습 니 다.
void luaext_open(lua_State* L)
{
#ifdef _DEBUG
	int nStackTop = lua_gettop(L);
#endif
	//	push key
	lua_pushlightuserdata(L, GetLuaFunctionRefKey());	//	stack: key
	//	push value
	lua_newtable(L);	//	stack: key table
	//	set global table key
	lua_rawset(L, LUA_REGISTRYINDEX);	//	stack:
#ifdef _DEBUG
	assert(nStackTop == lua_gettop(L));
#endif
}

그리고 우리 가 실현 하고 자 하 는 것 은 바로 lua 함 수 를 이 표 에 등록 하 는 것 이다.간단 합 니 다. 이 table 의 값 을 설정 하면 됩 니 다.
int luaext_registerLuaFunction(lua_State* L, int _nFuncIndex)
{
	if(_nFuncIndex < 0)
	{
		return 0;
	}
	if(!lua_isfunction(L, _nFuncIndex))
	{
		return 0;
	}

	//	push key
	lua_pushlightuserdata(L, GetLuaFunctionRefKey());	//	stack: func ... key
	//	get ref table
	lua_rawget(L, LUA_REGISTRYINDEX);		//	stack: func ... reftable

	if (!lua_istable(L, -1))
	{
		return 0;
	}

	//	push new key
	int nRefId = GetLuaFunctionRefId();
	lua_pushnumber(L, nRefId);			//	stack: func ... reftable key
	//	copy function value from stack
	lua_pushvalue(L, _nFuncIndex);		//	stack: func ... reftable key value
	//	set key
	lua_rawset(L, -3);	//	stack: func ... reftable
	//	pop table
	lua_pop(L, 1);

	return nRefId;
}

등록 을 했 으 니 반 등록 도 해 야 하고 간단 합 니 다. key = nil 을 설정 하면 됩 니 다.
void luaext_unregisterLuaFunctionByRefId(lua_State* L, int _nRefId)
{
#ifdef _DEBUG
	int nStackTop = lua_gettop(L);
#endif
	//	push key
	lua_pushlightuserdata(L, GetLuaFunctionRefKey());	//	stack: func ... key
	//	get ref table
	lua_rawget(L, LUA_REGISTRYINDEX);		//	stack: func ... reftable

	if (!lua_istable(L, -1))
	{
		return;
	}

	//	push the key
	lua_pushnumber(L, _nRefId);	//	stack: reftable key
	//	push nil
	lua_pushnil(L);			//	stack: reftable key nil
	//	set nil
	lua_rawset(L, -3);
	//	pop reftable
	lua_pop(L, 1);

#ifdef _DEBUG
	assert(lua_gettop(L) == nStackTop);
#endif
}

이 반 등록 은 ref 에 따라 반 등록 한 것 입 니 다. 물론 func 에 따라 반 등록 을 해 야 할 수도 있 습 니 다. 실현 도 간단 합 니 다. table 을 옮 겨 다 니 며 nil 을 설정 하면 됩 니 다.
int luaext_unregisterLuaFunction(lua_State* L, int _nFuncIndex)
{
	if(_nFuncIndex < 0)
	{
		return 0;
	}
	if(!lua_isfunction(L, _nFuncIndex))
	{
		return 0;
	}

	int nCount = 0;

	//	push key
	lua_pushlightuserdata(L, GetLuaFunctionRefKey());	//	stack: key
	//	get ref table
	lua_rawget(L, LUA_REGISTRYINDEX);		//	stack: reftable

	if (!lua_istable(L, -1))
	{
		return 0;
	}

	//	push reftable index
	int nStackTop = lua_gettop(L);

	//	push init key
	lua_pushnil(L);		//	stack: reftable nil_key

	while(lua_next(L, nStackTop))
	{
		//	stack: reftable key value
		if(lua_isfunction(L, -1))
		{
			//	valid function
			if(lua_equal(L, _nFuncIndex, -1))
			{
#ifdef _DEBUG
				int nTop = lua_gettop(L);
#endif
				//	set refFunc[key] = nil
				//	push key
				lua_pushvalue(L, -2);
				//	push nil
				lua_pushnil(L);
				//	stack: reftable key value key nil
				lua_rawset(L, -5);	//	stack: reftable key value

#ifdef _DEBUG
				assert(lua_gettop(L) == nTop);
#endif
				++nCount;
			}
		}

		//	pop the value, and use the key to get the next key
		lua_pop(L, 1);	//	stack: reftable key 
	}

#ifdef _DEBUG
	assert(lua_gettop(L) == nStackTop);
#endif

	return nCount;
}

이 일 을 해 냈 으 니 우리 가 사용 할 때 lua 가 필요 하 다.getglobal 과 유사 한 함수 입 니 다.getLua Function ByRefId 에서 push 가 호출 할 함 수 를 lua 창고 에 구현 합 니 다.
int luaext_getLuaFunctionByRefId(lua_State* L, int _nRefId)
{
#ifdef _DEBUG
	int nStackTop = lua_gettop(L);
#endif

	//	push key
	lua_pushlightuserdata(L, GetLuaFunctionRefKey());	//	stack: key
	//	get ref table
	lua_rawget(L, LUA_REGISTRYINDEX);		//	stack: reftable

	if (!lua_istable(L, -1))
	{
		return 0;
	}

	//	push key
	lua_pushnumber(L, _nRefId);	//	stack: reftable key
	//	get value
	lua_rawget(L, -2);		//	stack: reftable (value or nil)

	int nRetId = 0;

	if(lua_isfunction(L, -1))
	{
		nRetId = _nRefId;

		//	stack: reftable value
		lua_remove(L, -2);	//	stack: value(func)

#ifdef _DEBUG
		assert(lua_gettop(L) == nStackTop + 1);
#endif
	}
	else
	{
		//	pop reftable and nil
		lua_pop(L, 2);
#ifdef _DEBUG
		assert(lua_gettop(L) == nStackTop);
#endif
	}

	return nRetId;
}

위 는 핵심 기능 의 간단 한 실현 이다.상부 에서 이 루어 지면 각자 의 생각 이 있 습 니 다. 링크 를 통 해 모든 등록 사건 의 ref 를 저장 하면 됩 니 다. 호출 할 때 모든 ref 를 호출 하면 저도 자세히 말 하지 않 겠 습 니 다.그리고 예전 에 사 용 했 던 여러 lua 를getglobal 과 등록 함수 명 방식 으로 호출 된 함 수 를 모두 재 구성 하고 또 하나의 구덩이 입 니 다.

좋은 웹페이지 즐겨찾기