<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/css" href="http://wiki2.linuxformat.ru/skins/common/feed.css?97"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://wiki2.linuxformat.ru/index.php?action=history&amp;feed=atom&amp;title=LXF125%3ALua</id>
		<title>LXF125:Lua - История изменений</title>
		<link rel="self" type="application/atom+xml" href="http://wiki2.linuxformat.ru/index.php?action=history&amp;feed=atom&amp;title=LXF125%3ALua"/>
		<link rel="alternate" type="text/html" href="http://wiki2.linuxformat.ru/index.php?title=LXF125:Lua&amp;action=history"/>
		<updated>2026-05-13T22:10:56Z</updated>
		<subtitle>История изменений этой страницы в вики</subtitle>
		<generator>MediaWiki 1.11.1</generator>

	<entry>
		<id>http://wiki2.linuxformat.ru/index.php?title=LXF125:Lua&amp;diff=11160&amp;oldid=prev</id>
		<title>Crazy Rebel: викификация, оформление, иллюстрация</title>
		<link rel="alternate" type="text/html" href="http://wiki2.linuxformat.ru/index.php?title=LXF125:Lua&amp;diff=11160&amp;oldid=prev"/>
				<updated>2010-11-18T14:23:40Z</updated>
		
		<summary type="html">&lt;p&gt;викификация, оформление, иллюстрация&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Новая статья&lt;/b&gt;&lt;/p&gt;&lt;div&gt;: '''''Lua''''' Язык программирования сценариев, встраиваемый в ваши приложения&lt;br /&gt;
&lt;br /&gt;
==''Lua'': Встроим его в код==&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Lua}}&lt;br /&gt;
&lt;br /&gt;
: '''Часть 4''': Вот уже четвертый номер мы пропагандируем ''Lua'' как хороший встраиваемый язык, и теперь пришла пора подтвердить слова делом. '''Андрей Боровский''' скрестит его с ''C'' и ''C++''&lt;br /&gt;
&lt;br /&gt;
Говорят, что когда Билл Гейтс и Пол Аллен писали первый интерпретатор ''Basic'' для «Альтаира», они не пользовались генераторами лексических и синтаксических анализаторов и формальными грамматиками, потому что не знали об их существовании. Тут можно усмотреть как проявление гениальности основателей Microsoft, так и отсутствие надлежащей квалификации. Как бы там ни было, современные программисты также могут наделять свои приложения встроенными интерпретаторами скриптовых языков, ничего не зная о принципах написания последних. Умные люди упростили решение этой задачи до такой&lt;br /&gt;
степени, что теперь результатами их труда могут пользоваться все желающие. Остается только надеяться, что с годами избалованные программисты не станут глупее.&lt;br /&gt;
&lt;br /&gt;
Все синтаксические красоты ''Lua'' вряд ли привлекли бы к нему внимание, если бы не главное: возможность встраивать интерпретатор в программы, написанные на ''C'' и других компилируемых языках. О том, что это дает разработчику, мы говорили в [[LXF122:LUA|LXF122]]. С точки зрения программного интерфейса, объединение ''Lua'' и ''C'' позволяет решить две (как правило, связанные) задачи: управление программой ''Lua'' из приложения на ''C'' и вызов из программ&lt;br /&gt;
''Lua'' функций, написанных на ''C'' (в этом случае можно сказать, что программа ''Lua'' управляет ''C''-кодом).&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF125_72_1.jpg|300px]]  Игра ''Unknown Horizon'' — пример программы, использующей интерпретатор ''Lua''.|Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
===Состояние и стек===&lt;br /&gt;
&lt;br /&gt;
Ядро интерпретатора ''Lua'' находится в библиотеке ''liblua''. Программа-интерпретатор, которой мы пользовались до сих пор (файл '''lua5.1'''), представляет собой лишь тоненькую обертку вокруг нее. Чтобы наделить программу на ''C'' возможностью использовать язык ''Lua'', нужно связать ее с ''liblua'' и задействовать экспортируемый библиотекой API. Прежде чем выполнять примеры из этой статьи, убедитесь, что файл '''liblua.so''' в вашей системе является ссылкой на библиотеку '''liblua.so.5.1'''. API'' C'' довольно заметно изменился при переходе от версии ''Lua'' 5.0 к 5.1, а в наших примерах мы будем использовать API последней версии. &lt;br /&gt;
&lt;br /&gt;
Два наиболее важных понятия в ''Lua C'' API – это «состояние Lua» (Lua state) и стек. Первое есть структура, содержащая сведения об интерпретаторе, к которым можно получить доступ из функции и макросов ''Lua'' API. Адрес данной структуры является обязательным параметром для всех функций и макросов ''Lua C'' API (и всегда передается в качестве первого аргумента, так что дальше мы не будем каждый раз о нем упоминать). Для тех, кто регулярно имеет дело с различными программными интерфейсами в стиле ''C'' (скажем, ''GTK''), структура, описывающая состояние ''Lua'', не представляет собой ничего необычного – ее аналоги, содержащие информацию о состоянии программируемого элемента (окна, кодека, драйвера устройства и тому подобного), есть практически везде. Указатель на структуру, описывающую состояние ''Lua'', можно рассматривать как дескриптор экземпляра интерпретатора ''Lua'' (только нужно помнить, что экземпляра как такового не существует).&lt;br /&gt;
&lt;br /&gt;
Если состояние ''Lua'' выглядит абстрактным понятием, то стек ''Lua'' еще более абстрактен. Как мы знаем, переменные ''Lua'' очень сильно отличаются от переменных ''C'', поэтому нет возможности установить прямое соответствие между таковыми в программе-хозяине и сценарии ''Lua''. Стек играет роль средства для обмена данными, и также является частью состояния ''Lua''. В него можно помещать элементы, которые затем могут быть извлечены в обратном порядке. Практически все функции ''Lua C'' API выполняют операции над элементами стека и помещают в него результат. Поскольку переменные ''Lua'' полиморфны, ячейки стека могут содержать данные любого типа, поддерживаемого ''Lua''. Прежде чем использовать данные из стека в программе на ''С'', необходимо убедиться, что они имеют требуемый тип. С помощью стека между программой на ''C'' и кодом ''Lua ''передаются не только простые переменные, но и ссылки на функции и таблицы, описывающие загруженные модули. Вот почему стек ''Lua'' является важнейшей концепцией всего API.&lt;br /&gt;
&lt;br /&gt;
Запутались? Все это не так сложно, как кажется. Рассмотрим пример программы на ''C'', загружающий скрипт ''Lua'' (файл '''runlua.c''' на LXFDVD):&lt;br /&gt;
&lt;br /&gt;
 #include &amp;lt;lua.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;lauxlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
 int main(void)&lt;br /&gt;
 {&lt;br /&gt;
   int result;&lt;br /&gt;
   lua_State * L;&lt;br /&gt;
   L = luaL_newstate();&lt;br /&gt;
   luaL_openlibs(L);&lt;br /&gt;
   result = luaL_loadfile(L, “script.lua”);&lt;br /&gt;
   if (result) { &lt;br /&gt;
   fprintf(stderr, “Ошибка загрузки: %s\n”, lua_tostring(L, -1));&lt;br /&gt;
   exit(1);&lt;br /&gt;
 }&lt;br /&gt;
 lua_pushnumber(L, 2);&lt;br /&gt;
 lua_setglobal(L, “var”);&lt;br /&gt;
 result = lua_pcall(L, 0, LUA_MULTRET, 0);&lt;br /&gt;
 if (result) {&lt;br /&gt;
   fprintf(stderr, “Ошибка выполнения: %s\n”, lua_tostring(L,-1));&lt;br /&gt;
   exit(1);&lt;br /&gt;
 }&lt;br /&gt;
 printf(“Успешное завершение\n”);&lt;br /&gt;
 lua_close(L);&lt;br /&gt;
 return EXIT_SUCCESS;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Здесь считывается файл '''script.lua''', создается глобальная переменная ''Lua'' '''var''' со значением 2 и выполняется ''Lua''-программа. Элементы ''Lua C'' API описаны в заголовочных файлах '''lua.h''' и '''lauxlib.h'''. Переменная '''L''' – это указатель на структуру, описывающую состояние ''Lua''. Саму структуру мы создаем с помощью функции '''luaL_newstate()'''. Функция '''luaL_openlibs()''' открывает стандартные библиотеки ''Lua'' для заданного состояния. Если ее не вызывать, загруженная программа ''Lua'' не сможет обращаться к элементам стандартных библиотек ''Lua'', например, функции '''print()'''. Вызов '''luaL_loadfile()''' загружает текст программы ''Lua'' из файла. В случае успеха функция возвращает '''0'''; ненулевое значение свидетельствует об ошибке.&lt;br /&gt;
&lt;br /&gt;
Библиотека ''Lua'' возвращает подробные текстовые описания всех обнаруженных ошибок, причем использует для этого стандартный механизм передачи данных между ''Lua'' и программой-хозяином, то есть стек. В случае возникновения ошибки мы читаем ее описание посредством функции '''lua_tostring()'''. Обратите внимание на ее второй аргумент. Как и в большинстве функций ''Lua ''API, имеющих дело с данными ''Lua'', в качестве источника сведений для '''lua_tostring()''' мы указываем ячейку стека. Они обозначаются индексами, причем начиная с единицы, а не с нуля. Вызов функции&lt;br /&gt;
&lt;br /&gt;
 lua_tostring(L, -1)&lt;br /&gt;
&lt;br /&gt;
преобразует в строку ''C'' значение, находящееся в верхней ячейке стека (т.е. попавшее в стек последним). Аналогично, конструкция&lt;br /&gt;
&lt;br /&gt;
 lua_tostring(L, 1)&lt;br /&gt;
&lt;br /&gt;
считывает значение, которое было помещено в стек первым. Ячейку, где находится самое последнее из помещенных в стек значений (и на которую ссылается индекс '''-1'''), мы называем вершиной стека. Ячейку, где находится самое первое помещенное в стек значение (самое старое, которому соответствует индекс '''1'''), мы называем дном. Документация ''Lua'' придерживается противоположных обозначений (то, что мы называем дном стека, там считается вершиной, и наоборот). В данном примере будет считано описание ошибки, которое помещается на вершину стека.&lt;br /&gt;
&lt;br /&gt;
Важно отметить, что функция '''lua_tostring()''' (а также '''lua_tonumber()''' и ей подобные) не удаляет значение из стека. При работе с функциями Lua API следует всегда помнить, как они влияют на стек. Библиотеки ''Lua'' не следят за переполнением стека – вы сами должны заботиться о том, чтобы в нем не было ничего лишнего. Для удаления из стека заданного значения предназначена функция '''lua_pop()'''. Мы не вызываем ее после '''lua_tostring()''' только потому, что программа в этом случае все равно завершится и очищать стек специально нет необходимости.&lt;br /&gt;
&lt;br /&gt;
Если текст программы загружен успешно, функция '''luaL_loadfile()''' создает выполняемый интерпретатором ''Lua'' фрагмент и помещает его на вершину стека. Далее мы создаем глобальную переменную '''var'''. Функция '''lua_pushnumber()''' помещает в стек числовое значение. Макрос '''lua_setglobal()''' создает глобальную переменную и присваивает ей значение из ячейки, находящейся на вершине стека. Если мы посмотрим определение макроса '''lua_setglobal()''', то увидим, что он сводится к вызову '''lua_setfield()'''. Первым аргументом этой функции является указатель на структуру,&lt;br /&gt;
описывающую состояние ''Lua'', вторым – индекс таблицы, в которую добавляется переменная, а третьим – строка ''C'' с ее именем. Позволю себе напомнить, что все переменные ''Lua'' являются элементами каких-либо таблиц. Так, глобальные переменные содержатся в '''_G''' ([[LXF124:LUA|LXF124]]) – именно с этой таблицей и работает макрос '''lua_setglobal()'''. Разумеется, с помощью функции '''lua_setfield()''' (и макроса '''lua_setglobal()''') можно не только создавать новые переменные, но и модифицировать значения уже существующих. С помощью этих же функций можно уничтожать переменные ''Lua''. Делается это так же, как и внутри ''Lua''-кода, то есть путем присвоения переменной значения '''nil'''. Для записи его в стек предназначена специальная функция '''lua_pushnil()'''. Функция '''lua_setfield()''' удаляет значение с вершины стека, так что вызов '''lua_pop()''' после нее не нужен.&lt;br /&gt;
&lt;br /&gt;
Функция '''lua_pcall()''' выполняет самую волшебную часть нашей программы – запускает сценарий ''Lua'' на выполнение. Второй ее аргумент – число параметров, переданных выполняемому фрагменту (в нашем примере – '''0'''), третий – число значений, которые возвращает фрагмент (мы используем константу '''LUA_MULTRET''', указывающую, что оно может быть переменным).&lt;br /&gt;
&lt;br /&gt;
Помимо функции '''lua_pcall()''', API предоставляет нам '''lua_call()'''. Те, кто читал предыдущую статью, наверняка уже догадались, в чем разница между ними. Функция '''lua_pcall()''' выполняет загруженный код в «защищенном режиме», то есть подавляет все возникшие во время выполнения кода ''Lua'' ошибки, а не передает их на более высокий уровень. Но откуда функция '''lua_pcall()''' знает, какой фрагмент кода ''Lua'' она должна выполнить? В процессе&lt;br /&gt;
ее вызова из стека извлекаются аргументы, переданные фрагменту кода ''Lua'' (если они есть), а после них '''lua_pcall()''' ожидает увидеть ссылку на сам фрагмент. Она также извлекается из стека, и на ее месте оказываются значения, возвращенные выполненным фрагментом. Последний аргумент '''lua_pcall()''' – индекс в стеке функции ''Lua'', используемой для обработки ошибок. Если он равен '''0''', то в случае возникновения ошибки на вершине стека оказывается текстовое описание, которое мы выводим так же, как и в случае с '''luaL_loadfile()'''. Теперь нетрудно понять, как интерпретатор ''Lua'' выполняет несколько фрагментов программы, содержащихся в разных файлах, в едином контексте. Все, что для этого нужно – вызвать несколько функций '''lua_[p]call()''' с одной и той же переменной, описывающей состояние интерпретатора ''Lua''. Наконец, мы уничтожаем структуру, описывающую состояние ''Lua'', функцией '''lua_close()'''.&lt;br /&gt;
&lt;br /&gt;
Файл '''script.lua''', который мы загружаем на выполнение в программе-примере, может содержать любой корректный фрагмент программы ''Lua''. Нашу среду выполнения ''Lua'' отличает то, что фрагменту доступна глобальная переменная '''var'''. Это можно проверить с помощью простейшей конструкции:&lt;br /&gt;
&lt;br /&gt;
 print(“переменная var”, var)&lt;br /&gt;
&lt;br /&gt;
Сохранив эту строку в файле '''script.lua''', скомпилируйте нашу ''C''-программу:&lt;br /&gt;
&lt;br /&gt;
 gcc runlua.c -o runlua -llua&lt;br /&gt;
&lt;br /&gt;
Наберите '''./runlua''' и убедитесь, что приложение работает. Попробуйте отредактировать текст '''script.lua''' и посмотрите, как наша&lt;br /&gt;
программа реагирует на различные ошибки в коде ''Lua''.&lt;br /&gt;
&lt;br /&gt;
===И снова калькулятор===&lt;br /&gt;
&lt;br /&gt;
В прошлый раз мы использовали возможности ''Lua'' для создания программы-калькулятора. Теперь давайте попробуем применить ''Lua'' для добавления функций калькулятора в приложение ''C++'' (файл '''calc.cpp'''):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=c&amp;gt;&lt;br /&gt;
 #include &amp;lt;iostream&amp;gt;&lt;br /&gt;
 #include &amp;lt;string&amp;gt;&lt;br /&gt;
 extern “C” {&lt;br /&gt;
 #include “lualib.h”&lt;br /&gt;
 #include “lauxlib.h”&lt;br /&gt;
 }&lt;br /&gt;
 using namespace std;&lt;br /&gt;
 size_t l;&lt;br /&gt;
 const char * reader (lua_State *L, void *data, size_t *size) {&lt;br /&gt;
   char * result;&lt;br /&gt;
   * size = l;&lt;br /&gt;
   if (!l)&lt;br /&gt;
     result = 0;&lt;br /&gt;
   else&lt;br /&gt;
     result = (char *) data;&lt;br /&gt;
   l = 0;&lt;br /&gt;
   return result;&lt;br /&gt;
 }&lt;br /&gt;
 int main()&lt;br /&gt;
 {&lt;br /&gt;
   int result;&lt;br /&gt;
   lua_State * L;&lt;br /&gt;
   L = luaL_newstate();&lt;br /&gt;
   luaL_openlibs(L);&lt;br /&gt;
   while (true) {&lt;br /&gt;
     cout &amp;lt;&amp;lt; “Введи те строку или на жми те Ctrl-C” &amp;lt;&amp;lt; endl;&lt;br /&gt;
     string s;&lt;br /&gt;
     cin &amp;gt;&amp;gt; s;&lt;br /&gt;
     s = “do return “ + s + “ end \0”;&lt;br /&gt;
     l = s.length() + 1;&lt;br /&gt;
     result = lua_load(L, reader, &amp;amp;s[0], “calc”);&lt;br /&gt;
     if (result) {&lt;br /&gt;
       cout &amp;lt;&amp;lt; lua_tostring(L, -1) &amp;lt;&amp;lt; endl;&lt;br /&gt;
     }&lt;br /&gt;
     else {&lt;br /&gt;
       result = lua_pcall(L, 0, 1, 0);&lt;br /&gt;
       if (result != LUA_ERRRUN)&lt;br /&gt;
         cout &amp;lt;&amp;lt; lua_tonumber(L, -1) &amp;lt;&amp;lt; endl;&lt;br /&gt;
       else&lt;br /&gt;
         cout &amp;lt;&amp;lt; lua_tostring(L, -1) &amp;lt;&amp;lt; endl;&lt;br /&gt;
     }&lt;br /&gt;
     lua_pop(L, 1);&lt;br /&gt;
   }&lt;br /&gt;
   lua_close(L);&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Программа считывает строку со стандартного потока ввода и пытается вычислить содержащееся в ней математическое выражение (а на самом деле – все, что догадался набрать пользователь, так что будьте осторожны с этим в реальных приложениях!). Наш микрокалькулятор принимает выражения вида 2*(3+4), math.sin(3.14) и им подобные. Работа выполняется в бесконечном цикле, из которого можно выйти с помощью '''Ctrl+C'''.&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, что в программе, написанной на ''C++'', нужно явным образом указать, что функции ''Lua'' API экспортируются в формате ''C''. После того как мы считали строку (переменная '''s'''), нужно скомпилировать ее в функцию ''Lua''. В калькуляторе, написанном на чистом ''Lua'', для этого можно было использовать специальные функции. В ''Lua C'' API такие тоже были (например, '''lua_dostring())''', но теперь они признаны устаревшими. Вместо них следует использовать '''lua_load()''', которая умеет загружать исходный текст программы ''Lua'' из любого источника с помощью специальной вспомогательной функции. В нашем примере это '''reader()'''. При каждом вызове она должна вернуть указатель на новый фрагмент исходного текста программы ''Lua''. Длина очередного фрагмента возвращается в параметре '''size'''. Параметр '''data''' представляет собой указатель на данные, определенные программистом. Функция '''reader()''' сигнализирует о том, что она прочитала весь исходный текст, возвращая значение '''NULL'''. При первом вызове наша функция просто преобразует введенную пользователем программы строку ''C++'' в '''char *''' и возвращает ее длину. При втором вызове '''reader()''' сразу же возвращает '''NULL'''.&lt;br /&gt;
&lt;br /&gt;
Вернемся к '''lua_load()'''. Ее второй параметр – адрес вспомогательной функции для чтения исходного текста, третий – адрес данных для вспомогательной функции. Далее следует строка с именем загружаемого фрагмента (можно передать пустую строку). Обработка ошибок, возникших во время выполнения функции '''lua_load()''', осуществляется так же, как и в случае с '''luaL_loadfile()'''. Аналогично, функция '''lua_load()''' создает выполняемый интерпретатором ''Lua'' фрагмент и помещает его на вершину стека. После завершения '''lua_pcall()''' стек содержит значение, вычисленное нашим калькулятором. В случае ошибки оно будет иметь тип '''nil''', и мы считываем его с верхушки стека с помощью вызова '''lua_tonumber()'''. Если вершина стека содержит нечисловое значение, вызов '''lua_tonumber()''' возвращает '''0'''. После этого нам остается только удалить значение из стека с помощью '''lua_pop()'''.&lt;br /&gt;
&lt;br /&gt;
===И наоборот===&lt;br /&gt;
&lt;br /&gt;
Посмотрим теперь, как вызвать из ''Lua'' функцию, написанную на ''C''. Разумеется, в ''Lua'' нельзя импортировать любую функцию из ''C''-библиотеки – слишком уж разные это языки программирования. Тем не менее, написать ''C''-функцию в «экспортном варианте» оказывается на удивление просто. Рассмотрим сначала исходный текст библиотеки '''testlib''' (файл '''testlib.c'''), написанной на ''C'':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=c&amp;gt;&lt;br /&gt;
 #include “lua.h”&lt;br /&gt;
 #include “lualib.h”&lt;br /&gt;
 #include “lauxlib.h”&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
 static int _system (lua_State *L)&lt;br /&gt;
 {&lt;br /&gt;
   int result = system(lua_tostring(L, -1));&lt;br /&gt;
   lua_pushinteger(L, result);&lt;br /&gt;
   return 1;&lt;br /&gt;
 }&lt;br /&gt;
 int luaopen_testlib(lua_State *L)&lt;br /&gt;
 {&lt;br /&gt;
   static const luaL_reg Map [] = {{“system”, _system},&lt;br /&gt;
 {NULL,NULL}} ;&lt;br /&gt;
   luaL_register(L, “testlib”, Map);&lt;br /&gt;
   return 1;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данная библиотека предоставляет ''Lua'' одну функцию – '''system()'''. Функция '''testlib.system()''' (под этим именем она будет доступна в ''Lua'') делает то же, что и ее тезка из стандартной библиотеки ''C'' (разумеется, в стандартной библиотеке ''Lua'' она тоже есть). Во избежание неоднозначностей, в нашей ''C''-библиотеке экспортируемой функции присвоено имя '''_system()'''.&lt;br /&gt;
 &lt;br /&gt;
Чтобы понять, как работает экспорт ''C''-функций, необходимо различать передачу аргументов и возврат значений в контексте ''C'' и те же действия в контексте ''Lua''. Единственным аргументом экспортируемой функции в контексте ''C'' должен быть указатель на структуру '''lua_State''', а возвращаемым значением (в контексте ''C'') – число значений, возвращаемых в контексте ''Lua''. Да, вы правильно поняли: в контексте ''Lua'' экспортируемая функция может получать произвольное количество аргументов различных типов и возвращать любое число значений. Все аргументы и значения в контексте ''Lua'' передаются, разумеется, через стек. Мы считываем единственный аргумент функции '''testlib.system()''' с вершины стека, превращаем его в строку, вызываем ''C''-функцию '''system()''' и помещаем результат выполнения функции в стек ''Lua''. Поскольку в контексте ''Lua'' наша функция всегда возвращает только одно значение, в ''C''-коде мы пишем '''return 1'''.&lt;br /&gt;
&lt;br /&gt;
Чтобы подготовить библиотеку к работе с ''Lua'', нам надо написать еще одну функцию – '''luaopen_libname()''', где '''libname''' соответствует имени библиотеки. Она будет вызвана интерпретатором ''Lua'' при загрузке нашей библиотеки. Именно она позволяет использовать ''C''-библиотеку как стандартный пакет ''Lua''.&lt;br /&gt;
&lt;br /&gt;
Массив '''Map''' состоит из пар «имя функции в контексте ''Lua'' – указатель на ''C''-функцию». Эти данные интерпретатор ''Lua'' будет использовать для вызова функции, написанной на ''C''. Между прочим, поскольку имя функции в библиотеке ''C'' не имеет значения для интерпретатора, функции, в принципе, можно экспортировать и из кода ''C++'', не указывая формат (это не касается '''luaopen_*()''', которую интерпретатор ищет по имени ''C''). Функция '''luaL_register()''' регистрирует новую библиотеку и помещает ссылку на соответствующий объект на вершину стека. Вторым аргументом функции '''luaL_register()''' должно быть имя библиотеки в контексте ''Lua'', которое может и не совпадать с именем разделяемого модуля.&lt;br /&gt;
&lt;br /&gt;
Для компиляции библиотеки скомандуем&lt;br /&gt;
&lt;br /&gt;
 gcc testlib.c -shared -o testlib.so&lt;br /&gt;
&lt;br /&gt;
Теперь можно перейти к ''Lua''-коду:&lt;br /&gt;
&lt;br /&gt;
 require “testlib”&lt;br /&gt;
 print(“Вызов функции C”)&lt;br /&gt;
 res = testlib.system(“/usr/bin/mc”)&lt;br /&gt;
 if res ~= 0 then&lt;br /&gt;
  print(“Код завершения программы”, res)&lt;br /&gt;
 else&lt;br /&gt;
  print(“Нормальный выход”)&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Наш модуль '''testlib''' подключается к программе ''Lua'' так же, как и обычные библиотеки ''Lua'' ([[LXF124:LUA|LXF124]]). Обратите внимание, что хотя&lt;br /&gt;
в библиотеке '''testlib''' и используются функции ''Lua'' API, при компиляции мы не связываем ее с '''liblua'''. В этом нет необходимости, так как библиотека '''testlib''' будет загружена интерпретатором в то же адресное пространство, что и '''liblua'''. Между прочим, экспортировать функции ''C'' в ''Lua'' можно не только из разделяемых библиотек, но и непосредственно из файла программы, загружающей код ''Lua'' на выполнение. В этом случае нам пригодится другая функция ''Lua'' API – '''lua_register()'''.&lt;br /&gt;
&lt;br /&gt;
Каким образом функция ''C'' может узнать, сколько аргументов ей передано? В этом ей поможет функция '''lua_gettop()''', которая возвращает число элементов в стеке. В момент вызова функции ''C'' оно равно количеству аргументов, переданных функции. Строго говоря, '''lua_gettop()''' возвращает индекс последней ячейки стека, которая в терминологии ''Lua'' именуется вершиной (в описании стека я, как и авторы многих руководств по ''Lua'', придерживался других обозначений: вершина – первый элемент стека). Этой функцией можно пользоваться и для того, чтобы узнать, не переполнен ли стек. Глубина стека ''Lua'' контролируется константой '''MAX_STACK''', значение которой невелико (обычно не больше 32), но для любого разумного использования этого должно быть достаточно. В конце концов, глубина стека математического сопроцессора у Intel составляет всего 8 ячеек.&lt;br /&gt;
&lt;br /&gt;
Встраивание скриптовых языков программирования в пользовательские программы вполне соответствует идеологии Unix, согласно которой все, что может быть настроено пользователем под свои нужды, должно быть не зашито в исходном коде программы, а вынесено в отдельные системы конфигурации. Язык ''Lua'' – простое и мощное средство, позволяющее наделить вашу программу такими возможностями. '''LXF'''&lt;/div&gt;</summary>
		<author><name>Crazy Rebel</name></author>	</entry>

	</feed>