2016-01-13 3 views
4

В C Я хочу вызвать функцию lua myFunction(), которая использует глобальную переменную x. Я хочу иметь возможность зарегистрировать переменную c (integer) непосредственно как эту глобальную переменную x.Bind C Integer to Lua global variable

Что-то вдоль линий:

demo.lua:

function myFunction() 
    return x + 3 
end 

demo.c:

int x = 0; 
lua_bindglob(L, "x", &x); 

for (x = 0; x < 100; ++x) 
{ 
    lua_getglobal(L, "myFunction"); 

    // here I call the function and it should evaluate 
    // to the current value of x (in c) 
    lua_pcall(L, 0, 1, 0);  
    int result = lua_tonumber(L, -1); 

    lua_pop(L, 1); 
} 

Я знаю, что я могу изменить Lua глобальные переменные следующим образом:

lua_pushnumber(L, 3); 
lua_setglobal(L, "x"); 

Но мне нужно иметь более прямой/более быстрый способ сделать это. Я получил подсказку о том, что LUA ligthuserdata может помочь здесь, но я не мог найти примеров для простых переменных.

EDIT: Поскольку я получаю выражение от ориентира я не хочу, чтобы изменить их: Смотрите примеры here:

+1

Я не знаю, что есть способ сделать прямо то, что вы хотите сделать. Я столкнулся с одной и той же проблемой несколько месяцев назад и закончил работу с таблицей/userdata с метатемой, в которой были метаметоды '__index' и' __newindex', определенные как функции доступа. –

+0

Мое предположение - целое число в Lua является объектом , таким образом, C-код должен иметь возможность видеть и модифицировать внутреннее повторение (может не отображаться в 32-битном int). Если вы измените значение в Lua, новое значение будет иметь новый адрес. Лучшим подходом было бы получить доступ к '' int' через 'FFI' --- интерфейс внешней функции. Это требует, по крайней мере, того, что C-код экспортирует данный элемент данных в качестве символа. Пожалуйста, следуйте http://luajit.org/ext_ffi_tutorial.html –

ответ

2

Лучшее, что вы собираетесь быть в состоянии получить это возможность создать произведение userdata (обычный, не светлый), который имеет метамод __call, который получит/установит значение C для вас.

Так что ваша функция будет выглядеть следующим образом:

function myFunction() 
    return x() + 3 
end 

Он также может иметь метаметоды оператор, определенный таким образом, что такие вещи, как x + 3 могли бы работать. Но нет никакого способа для голого x разрешить нужное вам значение.

Установка значения будет выглядеть так:

x(3) 

Там нет никакого способа, чтобы сделать что-то вроде x = 3 работы так, как вы хотите. Это всегда будет перезаписывать значение, о котором идет речь.

Использование __newindex и __index метаметодов не будет работать, потому что вы хотите, чтобы переменная быть глобальной.

В качестве альтернативы вы можете использовать LuaJIT и его интерфейс FFI.

+1

Даже с LuaJIT FFI, я думаю, что (глобальное) назначение ключей будет перепроверять переменную. –

+3

Я закончил с LuaJIT самым быстрым способом. Но все еще слишком медленно, чтобы превзойти экспрессию. – schoetbi

2

Если у вас есть только несколько переменных C, которые вы хотите получить от Lua, вы можете установить метатет с помощью __index и __newindex metamethods в таблице глобальных таблиц. Когда доступ к несуществующей глобальной переменной (get или set), эти метаметоды вызывают, и вам нужно выяснить, что делать, если посмотреть на второй параметр на эти метаметоды (имя переменной).

Пример кода модуля, который экспортирует одну переменную:

#include <string.h> 
#include <limits.h> 
#include <lua.h> 
#include <lauxlib.h> 


static int x = 0; 


static int myvar_index(lua_State* L) { 
    char const* key = lua_tostring(L, 2); 
    if(key != NULL && strcmp(key, "x") == 0) 
    lua_pushinteger(L, x); 
    else 
    lua_pushnil(L); 
    return 1; 
} 


static int myvar_newindex(lua_State* L) { 
    char const* key = lua_tostring(L, 2); 
    if(key != NULL && strcmp(key, "x") == 0) { 
    lua_Integer i = luaL_checkinteger(L, 3); 
    if(i > INT_MAX || i < INT_MIN) 
     luaL_error(L, "variable value out of range"); 
    x = i; 
    } else 
    lua_rawset(L, 1); 
    return 0; 
} 


int luaopen_myvar(lua_State* L) { 
    luaL_Reg const metamethods[] = { 
    { "__index", myvar_index }, 
    { "__newindex", myvar_newindex }, 
    { NULL, NULL } 
    }; 
#if LUA_VERSION_NUM < 502 
    lua_pushvalue(L, LUA_GLOBALSINDEX); 
    lua_newtable(L); 
    luaL_register(L, NULL, metamethods); 
#else 
    lua_pushglobaltable(L); 
    luaL_newlib(L, metamethods); 
#endif 
    lua_setmetatable(L, -2); 
    return 0; 
} 

Чем больше переменных C вы экспорта, более сложные в реализации Метаметод получить, и вы, вероятно, лучше использовать один из других предложенных подходов ,

Также обратите внимание, что таблица глобальных таблиц является общим ресурсом, поэтому вам нужно избегать/обрабатывать конфликты с другим кодом, который изменяет его метатебель. (I.e. повторно используемые модули просто не должны изменять общие ресурсы, но я думаю, что то же самое относится к глобальным переменным в C ...)

+0

Это повлияет на поведение по умолчанию для доступа к глобальным переменным нежелательным образом? –

+0

Это повлияет на поведение для доступа к * неопределенным * глобальным. Большинство глобальных переменных, с которыми вы работаете, имеют значения, отличные от нуля. Все это не затрагивает. Для доступа к глобальным глобальным глобальным значениям потребуется дополнительный вызов метаметода. – siffiejoe