Lua Call C Print

  • If pattern specifies no captures, then the whole match is produced in each call. As an example, the following loop will iterate over all the words from string s, printing one per line: s = 'hello world from Lua' for w in string.gmatch(s, '%a+') do print(w) end.
  • Print formatted data to stdout Writes the C string pointed by format to the standard output ( stdout ). If format includes format specifiers (subsequences beginning with% ), the additional arguments following format are formatted and inserted in the resulting string replacing their respective specifiers.

Jul 26, 2014 With Lua you can do this but also the opposite. While you may not want to use Lua for performance critical sections of code it makes sense to call code written in Lua in certain cases. Complex string manipulation comes to mind. The Lua Module to Call. For my wrapped C in Lua example, I used a simple counter object.

This page describes the API functions provided by the FFI library indetail. It's recommended to read through theintroduction and theFFI tutorial first.

Glossary

  • cdecl — An abstract C type declaration (a Luastring).
  • ctype — A C type object. This is a special kind ofcdata returned by ffi.typeof(). It serves as acdataconstructor when called.
  • cdata — A C data object. It holds a value of thecorresponding ctype.
  • ct — A C type specification which can be used formost of the API functions. Either a cdecl, a ctype or acdata serving as a template type.
  • cb — A callback object. This is a C data objectholding a special function pointer. Calling this function fromC code runs an associated Lua function.
  • VLA — A variable-length array is declared with a? instead of the number of elements, e.g. 'int[?]'.The number of elements (nelem) must be given when it'screated.
  • VLS — A variable-length struct is a struct Ctype where the last element is a VLA. The same rules fordeclaration and creation apply.

Declaring and Accessing External Symbols

External symbols must be declared first and can then be accessed byindexing a C librarynamespace, which automatically binds the symbol to a specificlibrary.

ffi.cdef(def)

Adds multiple C declarations for types or external symbols (namedvariables or functions). def must be a Lua string. It'srecommended to use the syntactic sugar for string arguments asfollows:

The contents of the string (the part in green above) must be asequence ofC declarations,separated by semicolons. The trailing semicolon for a singledeclaration may be omitted.

Please note that external symbols are only declared, but theyare not bound to any specific address, yet. Binding isachieved with C library namespaces (see below).

C declarations are not passed through a C pre-processor,yet. No pre-processor tokens are allowed, except for#pragma pack. Replace #define in existingC header files with enum, static constor typedef and/or pass the files through an externalC pre-processor (once). Be careful not to include unneeded orredundant declarations from unrelated header files.

ffi.C

This is the default C library namespace — note theuppercase 'C'. It binds to the default set of symbols orlibraries on the target system. These are more or less the same as aC compiler would offer by default, without specifying extra linklibraries.

Luaavg-5.1.tar.gz- Tutorial Source and Makefile for Linux.

On POSIX systems, this binds to symbols in the default or globalnamespace. This includes all exported symbols from the executable andany libraries loaded into the global namespace. This includes at leastlibc, libm, libdl (on Linux),libgcc (if compiled with GCC), as well as any exportedsymbols from the Lua/C API provided by LuaJIT itself.

On Windows systems, this binds to symbols exported from the*.exe, the lua51.dll (i.e. the Lua/C APIprovided by LuaJIT itself), the C runtime library LuaJIT was linkedwith (msvcrt*.dll), kernel32.dll,user32.dll and gdi32.dll.

clib = ffi.load(name [,global])

This loads the dynamic library given by name and returnsa new C library namespace which binds to its symbols. On POSIXsystems, if global is true, the library symbols areloaded into the global namespace, too.

If name is a path, the library is loaded from this path.Otherwise name is canonicalized in a system-dependent way andsearched in the default search path for dynamic libraries:

On POSIX systems, if the name contains no dot, the extension.so is appended. Also, the lib prefix is prependedif necessary. So ffi.load('z') looks for 'libz.so'in the default shared library search path.

On Windows systems, if the name contains no dot, the extension.dll is appended. So ffi.load('ws2_32') looks for'ws2_32.dll' in the default DLL search path.

Creating cdata Objects

The following API functions create cdata objects (type()returns 'cdata'). All created cdata objects aregarbage collected.

cdata = ffi.new(ct [,nelem] [,init...])
cdata = ctype([nelem,] [init...])

Creates a cdata object for the given ct. VLA/VLS typesrequire the nelem argument. The second syntax uses a ctype asa constructor and is otherwise fully equivalent.

The cdata object is initialized according to therules for initializers,using the optional init arguments. Excess initializers causean error.

Performance notice: if you want to create many objects of one kind,parse the cdecl only once and get its ctype withffi.typeof(). Then use the ctype as a constructor repeatedly.

Please note that an anonymous struct declaration implicitlycreates a new and distinguished ctype every time you use it forffi.new(). This is probably not what you want,especially if you create more than one cdata object. Different anonymousstructs are not considered assignment-compatible by theC standard, even though they may have the same fields! Also, theyare considered different types by the JIT-compiler, which may cause anexcessive number of traces. It's strongly suggested to either declarea named struct or typedef with ffi.cdef()or to create a single ctype object for an anonymous structwith ffi.typeof().

ctype = ffi.typeof(ct)

Creates a ctype object for the given ct.

This function is especially useful to parse a cdecl only once and thenuse the resulting ctype object as a constructor.

cdata = ffi.cast(ct, init)

Creates a scalar cdata object for the given ct. The cdataobject is initialized with init using the 'cast' variant ofthe C type conversionrules.

This functions is mainly useful to override the pointer compatibilitychecks or to convert pointers to addresses or vice versa.

ctype = ffi.metatype(ct, metatable)

Creates a ctype object for the given ct and associates it witha metatable. Only struct/union types, complex numbersand vectors are allowed. Other types may be wrapped in astruct, if needed.

The association with a metatable is permanent and cannot be changedafterwards. Neither the contents of the metatable nor thecontents of an __index table (if any) may be modifiedafterwards. The associated metatable automatically applies to all usesof this type, no matter how the objects are created or where theyoriginate from. Note that pre-defined operations on types haveprecedence (e.g. declared field names cannot be overridden).

All standard Lua metamethods are implemented. These are called directly,without shortcuts and on any mix of types. For binary operations, theleft operand is checked first for a valid ctype metamethod. The__gc metamethod only applies to struct/uniontypes and performs an implicit ffi.gc()call during creation of an instance.

cdata = ffi.gc(cdata, finalizer)

Associates a finalizer with a pointer or aggregate cdata object. Thecdata object is returned unchanged.

This function allows safe integration of unmanaged resources into theautomatic memory management of the LuaJIT garbage collector. Typicalusage:

A cdata finalizer works like the __gc metamethod for userdataobjects: when the last reference to a cdata object is gone, theassociated finalizer is called with the cdata object as an argument. Thefinalizer can be a Lua function or a cdata function or cdata functionpointer. An existing finalizer can be removed by setting a nilfinalizer, e.g. right before explicitly deleting a resource:

C Type Information

The following API functions return information about C types.They are most useful for inspecting cdata objects.

size = ffi.sizeof(ct [,nelem])

Returns the size of ct in bytes. Returns nil ifthe size is not known (e.g. for 'void' or function types).Requires nelem for VLA/VLS types, except for cdata objects.

align = ffi.alignof(ct)

Lua - Find Out Calling Function - Stack Overflow

Returns the minimum required alignment for ct in bytes.

ofs [,bpos,bsize] = ffi.offsetof(ct, field)

Returns the offset (in bytes) of field relative to the startof ct, which must be a struct. Additionally returnsthe position and the field size (in bits) for bit fields.

status = ffi.istype(ct, obj)

Returns true if obj has the C type given byct. Returns false otherwise.

C type qualifiers (const etc.) are ignored. Pointers arechecked with the standard pointer compatibility rules, but without anyspecial treatment for void *. If ct specifies astruct/union, then a pointer to this type is accepted,too. Otherwise the types must match exactly.

Note: this function accepts all kinds of Lua objects for theobj argument, but always returns false for non-cdataobjects.

Utility Functions

err = ffi.errno([newerr])

Returns the error number set by the last C function call whichindicated an error condition. If the optional newerr argumentis present, the error number is set to the new value and the previousvalue is returned.

This function offers a portable and OS-independent way to get and set theerror number. Note that only some C functions set the errornumber. And it's only significant if the function actually indicated anerror condition (e.g. with a return value of -1 orNULL). Otherwise, it may or may not contain any previously setvalue.

You're advised to call this function only when needed and as close aspossible after the return of the related C function. Theerrno value is preserved across hooks, memory allocations,invocations of the JIT compiler and other internal VM activity. The sameapplies to the value returned by GetLastError() on Windows, butyou need to declare and call it yourself.

str = ffi.string(ptr [,len])

Learn Lua C

Creates an interned Lua string from the data pointed to byptr.

If the optional argument len is missing, ptr isconverted to a 'char *' and the data is assumed to bezero-terminated. The length of the string is computed withstrlen().

Otherwise ptr is converted to a 'void *' andlen gives the length of the data. The data may containembedded zeros and need not be byte-oriented (though this may causeendianess issues).

This function is mainly useful to convert (temporary)'const char *' pointers returned byC functions to Lua strings and store them or pass them to otherfunctions expecting a Lua string. The Lua string is an (interned) copyof the data and bears no relation to the original data area anymore.Lua strings are 8 bit clean and may be used to hold arbitrary,non-character data.

Performance notice: it's faster to pass the length of the string, ifit's known. E.g. when the length is returned by a C call likesprintf().

ffi.copy(dst, src, len)
ffi.copy(dst, str)

Copies the data pointed to by src to dst.dst is converted to a 'void *' and srcis converted to a 'const void *'.

In the first syntax, len gives the number of bytes to copy.Caveat: if src is a Lua string, then len must notexceed #src+1.

In the second syntax, the source of the copy must be a Lua string. Allbytes of the string plus a zero-terminator are copied todst (i.e. #src+1 bytes).

Performance notice: ffi.copy() may be used as a faster(inlinable) replacement for the C library functionsmemcpy(), strcpy() and strncpy().

ffi.fill(dst, len [,c])

Fills the data pointed to by dst with len constantbytes, given by c. If c is omitted, the data iszero-filled.

Performance notice: ffi.fill() may be used as a faster(inlinable) replacement for the C library functionmemset(dst, c, len). Please note the differentorder of arguments!

Target-specific Information

status = ffi.abi(param)

Returns true if param (a Lua string) applies for thetarget ABI (Application Binary Interface). Returns falseotherwise. The following parameters are currently defined:

ParameterDescription
32bit32 bit architecture
64bit64 bit architecture
leLittle-endian architecture
beBig-endian architecture
fpuTarget has a hardware FPU
softfpsoftfp calling conventions
hardfphardfp calling conventions
eabiEABI variant of the standard ABI
winWindows variant of the standard ABI

ffi.os

Contains the target OS name. Same contents asjit.os.

ffi.arch

Contains the target architecture name. Same contents asjit.arch.

Methods for Callbacks

The C types for callbackshave some extra methods:

cb:free()

Free the resources associated with a callback. The associated Luafunction is unanchored and may be garbage collected. The callbackfunction pointer is no longer valid and must not be called anymore(it may be reused by a subsequently created callback).

cb:set(func)

Associate a new Lua function with a callback. The C type of thecallback and the callback function pointer are unchanged.

This method is useful to dynamically switch the receiver of callbackswithout creating a new callback each time and registering it again (e.g.with a GUI library).

Extended Standard Library Functions

The following standard library functions have been extended to workwith cdata objects:

n = tonumber(cdata)

Converts a number cdata object to a double and returns it asa Lua number. This is particularly useful for boxed 64 bitinteger values. Caveat: this conversion may incur a precision loss.

s = tostring(cdata)

Returns a string representation of the value of 64 bit integers('nnnLL' or 'nnnULL') orcomplex numbers ('re±imi'). Otherwisereturns a string representation of the C type of a ctype object('ctype<type>') or a cdata object('cdata<type>: address'), unless youoverride it with a __tostring metamethod (seeffi.metatype()).

iter, obj, start = pairs(cdata)
iter, obj, start = ipairs(cdata)

Calls the __pairs or __ipairs metamethod of thecorresponding ctype.

Extensions to the Lua Parser

The parser for Lua source code treats numeric literals with thesuffixes LL or ULL as signed or unsigned 64 bitintegers. Case doesn't matter, but uppercase is recommended forreadability. It handles both decimal (42LL) and hexadecimal(0x2aLL) literals.

The imaginary part of complex numbers can be specified by suffixingnumber literals with i or I, e.g. 12.5i.Caveat: you'll need to use 1i to get an imaginary part withthe value one, since i itself still refers to a variablenamed i.


The lua source can be found at the lua website here. We'll be using the latest version, 5.2.3 (though other recent versions of Lua will behave similarly).

Once you have the latest lua source, it's time to build it. (Yes, you could just download header files and the .dll, but what's the fun in that? When available, it's always better to have the source, that way you can see how things are really working -- and you can debug more easily). Using visual studio:

  • Open up Visual Studio, and create a new project
    • Create a win 32 console application
    • In the Project Creation wizard, check the 'static library' radio button to build as a static library.
  • Add the lua source to the project. Just dragging the files directly from their folders into the project works well for this.
  • There are two source files that you don't need: lua.c and luac.c. These files contain the main program for the command line interpreter and the bytecode compiler, respectively. You can remove this files from the project if you wish. If you are building as a static library, having more than one main won't be a problem. However, if you are building as an executable, then you will need to exclude one of these files from the project. Right-click on them in the project explorer and select 'Exclude from Project'

You now have a project that you can add to any solution that needs lua. Once you have added the lua project to your game, you need to do a few more steps:

  • In the properties for the project that is using lua, be sure that the directory that contains the lua .h files is included in the set of include paths. If at all possible, make these paths relative, and not absolute
  • Your project will need to get at the .lib files for the lua. There are a few ways to do this:
    • Add a reference from your project to the lua project. Right-click on your project in the project explorer, and select References:
      Add a new reference:
      Select the lua project:
    • Or, add Lua.lib to 'Additional Dependencies' (in the Librarian/Genrerl tab of the Project Property Pages) and add the directory where Lua.lib lives to 'Additional Library Directories' (also in the Librarian/Genrerl tab of the Project Property Pages).
Source

Once we have build Lua, and set up our project dependencies correctly, we are ready to use in on our application,


First off, we need to include the proper header files. Since Lua is ANSI C, if we are coding in C++, we will need to enclose the #includes in extern 'C':

Lua Call C Printable


Everything that we need to mantain the current state of the interprer (all global tables, etc) is stored in a variable of type lua_State. The first thing we need to do is create an initial state (essentially, an instantiation of the lua interpreter), which is done by the call:


Every time we want to access the interpreter, we need to pass in this state variable. We can actually have as many instances of Lua state variables as we like (for instance, if we wanted to run separate instances of the interpreter on separate processors, or we wanted different scripts to have different global namespaces), though typically people just use one instance of the interpreter that all scripts use. The global tables in this state variable contain all 'core' functions, but none of the libraries. The libraries contain a bunch of important functions -- including everything in math, and i/o functions like print -- so we'd like to load them. We can load libraries with the call:


So, now we have the skeleton of a main function:

We are ready to start using lua!


We will start with the simplest way to use lua -- have the interpreter execute a file. This is functionally equivalent to the dofile command from within lua (and unsurprisingly, has the same name!). To execute the file 'test.lua', we can use the call:

Note that if we are using relative paths other than absolute paths under windows, then the system will look in the current working directory -- which is the directory that the executable file is in (if you double-click on the executable), or the directory that the project is in (if you run from within Visual Studio) You can, of course, change the working directory that the debugger uses under the project settings in Visual Studio.

So, if we use the following myFile.lua:

when the command luaL_dofile(L, 'myFile.lua') is executed, the following will be printed out

Note that the dofile command not only computes these values and prints them out, it also adds the fib function to the global namespace of our lua enviornment (stored in the C variable L).

We can also call lua functions directly from C/C++, and get back the return values to use in our C/C++ code. To call a lua function we:

  • Push the function on the top of the lua stack, using a call to
    • lua_getGlobal(lua_state *L, char *globalName)
  • Push the arguments to the function on the lua stack, using the functions:
    • lua_pushnumber(lua_state *L, float number)
    • lua_pushstring(lua_state *L, char *str)
    • lua_pushboolean(lua_state *L, bool)
    • lua_pushuserdata(lua_state *L, void *userdata)
    • lua_pushnil(lua_state *L)
  • Call the function, using the function:
    • lua_call(lua_state *L, int numArguments, int numReturnValues)
      We need to pass in both the number of arguments that we are passing in, and the number of arguments that we expect in return. Lua is very loose about the number of arguments and return value, but C/C++ is less so -- hence we need to be explicit when calling lua from C/C++.
  • Extract the return values, using the functions:
    • int lua_tointeger(lua_state *L, int stackLocation)
      Grab an integer value off the lua stack. The first return value is at index -1, the second return value is at index -2, and so on.
    • double lua_tonumber(lua_state *L, int stackLocation)
      Grab a double value off the lua stack. The first return value is at index -1, the second return value is at index -2, and so on.
    • const char *lua_tolstring(lua_state *L, int stackLocation)
      Grab a string value of the lua stack
    • int lua_toboolean(lua_state *L, int stackLocation)
      Grab a boolean value off the lua stack
      Note that these functions 'peek' at the lua stack, they don't actually remove any values from the stack. (That is done by the next function)
  • Pop the return value(s) off the top of the sack (this is just to clean up) with a call to
    • lua_pop(lua_state *L, int numReturnValsToPop);
Let's take a look at how we might call the fib function defined in the previous section to find the 13th Fibonacci number:

Let's look at a second example. Assume that we had defined the following lua function add (that we could define by calling lua_dofile):

We could call this function to add from C/C++ with the code:

So now you could write scripts that you can call from your game engine. However, these scripts won't be very useful if they can't interact with your game objects -- you need a way for your scripts to affect the game world. To do that, you need to be able to call C/C++ functions from lua. Since Lua and C++ have very different conventions for how functions are called, there is a little bit of wrapper work that needs to be done. First, write a C function that takes as input a Lua state variable (the parameters for the function will need to be extracted by hand from the lua stack -- this is slightly tedious, but not too difficult.) Then, the function will need to be registered with lua.

Step 1: Writing a C function that Lua can call

C/C++ functions that are called from lua need to take as an input parameter the lua state. The parameters can be examined on the call stack using the functions lua_tointeger, lua_tonumber, etc (described above). The first parameter is at index 1, the second parameter is at index 2, and so on. Once we have extracted the parameters, we do our calculation, and then push the result on the top of the stack.

Cached

Let's look at a slightly more complicated C function. We can write C functions that takes a variable number of parameters, and returns more than one return value. While the previous function assumed that we were passed in two parameters, we can instead query the lua state to see how many parameters were actually passed into the function. The number of parameters is stored on the top of the stack, which can be accessed by a call to lua_gettop(lua_state *L). Let's look at a function that takes in multiple parameters, and calculates the sum and average of all parameters that were passed in:

Step 2: Registering the C function for lua

Once we have written the function, we just need to register it with lua. That is, we need to add the name of the function to the global lua namespace, and provide a pointer to the function so that lua cal access it. There is a helpful macro for this: lua_register(lua_state *L, const char *name, functionPointer fn). So, to register the above two functions:

Step 3: Calling the C funcion from lua

This part is easy -- once the function is registered, lua can call it like any other function.

So, the complete round trip is:

  • Start the lua interpreter
  • Register the C functions you want lua to use
  • Call a lua function from within C, either by a call to luaL_dofile, or by calling a lua function directly
  • The lua function that you called from C can access the C function

We can also send a string straight to the lua interpreter, and it will be executed just as if that string was in a file that was executed with a dofile. So, we could do something like:

and we would get the output:

We could thus create a braindead interpreter as follows:

Note that this would not work at all in a game environment! We will look at how to embed a command-line lua interpreter within a game next time. For now, this is enough for us to play around with a bit.

Now we are ready to get our fingers dirty!

  1. Download the following project, which contains a basic skeleton lua framework
  2. Write a function in C (exposed to Lua, much like average and cAdd) that takes as input an integer n, and returns all prime numbers less than or equal to n.
    • Test your primes function in the interpreter with 'print(primes(100))'
  3. Write a function in lua nthPrime, that takes as input a number n, and returns the nth prime number. So, nthPrime(6) should return 13. We'll define nthPrime(1) to be 2, and nthPrime(0) will be undefined. Your lua function should call the c primes function
    • Small change in how lua does variable numbers of arguments: From the notes

      Alas, this does not work. But we can fix it with a simple change:

  4. Write C code that computes the 100th prime number by calling the lua nthPrime function, and prints the value out using printf. So, C calling Lua that calls C.