TODO
C Language Support
TODO
C Type Conversion Rules
TODO
Initializers
Creating a cdata object with ffi.new() or the equivalent constructor syntax always initializes its contents, too. Different rules apply, depending on the number of optional initializers and the C types involved:
- If no initializers are given, the object is filled with zero bytes.
- Scalar types (numbers and pointers) accept a single initializer. The standard C type conversion rules apply.
- Valarrays (complex numbers and vectors) are treated like scalars when a single initializer is given. Otherwise they are treated like regular arrays.
- Aggregate types (arrays and structs) accept either a single compound initializer (Lua table or string) or a flat list of initializers.
- The elements of an array are initialized, starting at index zero. If a single initializer is given for an array, it's repeated for all remaining elements. This doesn't happen if two or more initializers are given: all remaining uninitialized elements are filled with zero bytes.
- The fields of a struct are initialized in the order of their declaration. Uninitialized fields are filled with zero bytes.
- Only the first field of a union can be initialized with a flat initializer.
- Elements or fields which are aggregates themselves are initialized with a single initializer, but this may be a compound initializer or a compatible aggregate, of course.
C Library Namespaces
A C library namespace is a special kind of object which allows access to the symbols contained in libraries. Indexing it with a symbol name (a Lua string) automatically binds it to the library.
TODO
Operations on cdata Objects
TODO
Garbage Collection of cdata Objects
All explicitly (ffi.new(), ffi.cast() etc.) or implicitly (accessors) created cdata objects are garbage collected. You need to ensure to retain valid references to cdata objects somewhere on a Lua stack, an upvalue or in a Lua table while they are still in use. Once the last reference to a cdata object is gone, the garbage collector will automatically free the memory used by it (at the end of the next GC cycle).
Please note that pointers themselves are cdata objects, however they are not followed by the garbage collector. So e.g. if you assign a cdata array to a pointer, you must keep the cdata object holding the array alive as long as the pointer is still in use:
ffi.cdef[[ typedef struct { int *a; } foo_t; ]] local s = ffi.new("foo_t", ffi.new("int[10]")) -- WRONG! local a = ffi.new("int[10]") -- OK local s = ffi.new("foo_t", a) -- Now do something with 's', but keep 'a' alive until you're done.
Similar rules apply for Lua strings which are implicitly converted to "const char *": the string object itself must be referenced somewhere or it'll be garbage collected eventually. The pointer will then point to stale data, which may have already beeen overwritten. Note that string literals are automatically kept alive as long as the function containing it (actually its prototype) is not garbage collected.
Objects which are passed as an argument to an external C function are kept alive until the call returns. So it's generally safe to create temporary cdata objects in argument lists. This is a common idiom for passing specific C types to vararg functions:
ffi.cdef[[
int printf(const char *fmt, ...);
]]
ffi.C.printf("integer value: %d\n", ffi.new("int", x)) -- OK
Memory areas returned by C functions (e.g. from malloc()) must be manually managed, of course. Pointers to cdata objects are indistinguishable from pointers returned by C functions (which is one of the reasons why the GC cannot follow them).
Current Status
The initial release of the FFI library has some limitations and is missing some features. Most of these will be fixed in future releases.
C language support is currently incomplete:
- C declarations are not passed through a C pre-processor, yet.
- The C parser is able to evaluate most constant expressions commonly found in C header files. However it doesn't handle the full range of C expression semantics and may fail for some obscure constructs.
- static const declarations only work for integer types up to 32 bits. Neither declaring string constants nor floating-point constants is supported.
- The long double C type is parsed correctly, but there's no support for the related conversions, accesses or arithmetic operations.
- Packed struct bitfields that cross container boundaries are not implemented.
- Native vector types may be defined with the GCC mode and vector_size attributes. But no operations other than loading, storing and initializing them are supported, yet.
- The volatile type qualifier is currently ignored by compiled code.
- ffi.cdef silently ignores all redeclarations.
The JIT compiler already handles a large subset of all FFI operations. It automatically falls back to the interpreter for unimplemented operations (you can check for this with the -jv command line option). The following operations are currently not compiled and may exhibit suboptimal performance, especially when used in inner loops:
- Array/struct copies and bulk initializations.
- Bitfield accesses and initializations.
- Vector operations.
- Lua tables as compound initializers.
- Initialization of nested struct/union types.
- Allocations of variable-length arrays or structs.
- Allocations of C types with a size > 64 bytes or an alignment > 8 bytes.
- Conversions from lightuserdata to void *.
- Pointer differences for element sizes that are not a power of two.
- Calls to non-cdecl or vararg C functions.
- Calls to C functions with aggregates passed or returned by value.
- Calls to C functions with 64 bit arguments or return values on 32 bit CPUs.
- tostring() for cdata types.
- The following ffi.* API functions: ffi.sizeof(), ffi.alignof(), ffi.offsetof().
Other missing features:
- Bit operations for 64 bit types.
- Arithmetic for complex numbers.
- User-defined metamethods for C types.
- Callbacks from C code to Lua functions.
- Atomic handling of errno.
- Passing structs by value to vararg C functions.
- C++ exception interoperability does not extend to C functions called via the FFI.