FFI: Finish FFI docs.
This commit is contained in:
@@ -33,8 +33,6 @@
|
||||
</li><li>
|
||||
<a href="ext_ffi_api.html">ffi.* API</a>
|
||||
</li><li>
|
||||
<a href="ext_ffi_int64.html">64 bit Integers</a>
|
||||
</li><li>
|
||||
<a href="ext_ffi_semantics.html">FFI Semantics</a>
|
||||
</li></ul>
|
||||
</li><li>
|
||||
@@ -86,22 +84,30 @@ Please use the FFI sub-topics in the navigation bar to learn more.
|
||||
It's really easy to call an external C library function:
|
||||
</p>
|
||||
<pre class="code">
|
||||
<span style="color:#000080;">local ffi = require("ffi")</span>
|
||||
ffi.cdef[[
|
||||
<span style="color:#00a000;font-weight:bold;">int printf(const char *fmt, ...);</span>
|
||||
local ffi = require("ffi") <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">①</span>
|
||||
ffi.cdef[[ <span style="color:#f0f4ff;">//</span><span style="color:#4040c0;">②</span>
|
||||
<span style="color:#00a000;">int printf(const char *fmt, ...);</span>
|
||||
]]
|
||||
<span style="color:#c06000;font-weight:bold;">ffi.C</span>.printf("Hello %s!", "world")
|
||||
ffi.C.printf("Hello %s!", "world") <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">③</span>
|
||||
</pre>
|
||||
<p>
|
||||
So, let's pick that apart: the first line (in blue) loads the FFI
|
||||
library. The next one adds a C declaration for the function. The
|
||||
part between the double-brackets (in green) is just standard
|
||||
C syntax. And the last line calls the named C function. Yes,
|
||||
it's that simple!
|
||||
So, let's pick that apart:
|
||||
</p>
|
||||
<p>
|
||||
<span style="color:#4040c0;">①</span> Load the FFI library.
|
||||
</p>
|
||||
<p>
|
||||
<span style="color:#4040c0;">②</span> Add a C declaration
|
||||
for the function. The part inside the double-brackets (in green) is
|
||||
just standard C syntax.
|
||||
</p>
|
||||
<p>
|
||||
<span style="color:#4040c0;">③</span> Call the named
|
||||
C function — Yes, it's that simple!
|
||||
</p>
|
||||
<p style="font-size: 8pt;">
|
||||
Actually, what goes on behind the scenes is far from simple: the first
|
||||
part of the last line (in orange) makes use of the standard
|
||||
Actually, what goes on behind the scenes is far from simple: <span
|
||||
style="color:#4040c0;">③</span> makes use of the standard
|
||||
C library namespace <tt>ffi.C</tt>. Indexing this namespace with
|
||||
a symbol name (<tt>"printf"</tt>) automatically binds it to the the
|
||||
standard C library. The result is a special kind of object which,
|
||||
@@ -120,7 +126,7 @@ So here's something to pop up a message box on Windows:
|
||||
<pre class="code">
|
||||
local ffi = require("ffi")
|
||||
ffi.cdef[[
|
||||
int MessageBoxA(void *w, const char *txt, const char *cap, int type);
|
||||
<span style="color:#00a000;">int MessageBoxA(void *w, const char *txt, const char *cap, int type);</span>
|
||||
]]
|
||||
ffi.C.MessageBoxA(nil, "Hello world!", "Test", 0)
|
||||
</pre>
|
||||
@@ -193,24 +199,24 @@ And here's the FFI version. The modified parts have been marked in
|
||||
bold:
|
||||
</p>
|
||||
<pre class="code">
|
||||
<b>local ffi = require("ffi")
|
||||
ffi.cdef[[
|
||||
typedef struct { uint8_t red, green, blue, alpha; } rgba_pixel;
|
||||
<b>local ffi = require("ffi")</b> <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">①</span>
|
||||
<b>ffi.cdef[[
|
||||
</b><span style="color:#00a000;">typedef struct { uint8_t red, green, blue, alpha; } rgba_pixel;</span><b>
|
||||
]]</b>
|
||||
|
||||
local function image_ramp_green(n)
|
||||
<b>local img = ffi.new("rgba_pixel[?]", n)</b>
|
||||
<b>local img = ffi.new("rgba_pixel[?]", n)</b> <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">②</span>
|
||||
local f = 255/(n-1)
|
||||
for i=<b>0,n-1</b> do
|
||||
<b>img[i].green = i*f</b>
|
||||
for i=<b>0,n-1</b> do <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">③</span>
|
||||
<b>img[i].green = i*f</b> <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">④</span>
|
||||
<b>img[i].alpha = 255</b>
|
||||
end
|
||||
return img
|
||||
end
|
||||
|
||||
local function image_to_grey(img, n)
|
||||
for i=<b>0,n-1</b> do
|
||||
local y = <b>0.3*img[i].red + 0.59*img[i].green + 0.11*img[i].blue</b>
|
||||
for i=<b>0,n-1</b> do <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">③</span>
|
||||
local y = <b>0.3*img[i].red + 0.59*img[i].green + 0.11*img[i].blue</b> <span style="color:#f0f4ff;">--</span><span style="color:#4040c0;">⑤</span>
|
||||
img[i].red = y; img[i].green = y; img[i].blue = y
|
||||
end
|
||||
end
|
||||
@@ -222,25 +228,37 @@ for i=1,1000 do
|
||||
end
|
||||
</pre>
|
||||
<p>
|
||||
Ok, so that wasn't too difficult: first, load the FFI library and
|
||||
declare the low-level data type. Here we choose a <tt>struct</tt>
|
||||
which holds four byte fields, one for each component of a 4x8 bit
|
||||
RGBA pixel.
|
||||
Ok, so that wasn't too difficult:
|
||||
</p>
|
||||
<p>
|
||||
Creating the data structure with <tt>ffi.new()</tt> is straightforward
|
||||
— the <tt>'?'</tt> is a placeholder for the number of elements
|
||||
of a variable-length array. C arrays are zero-based, so the
|
||||
indexes have to run from <tt>0</tt> to <tt>n-1</tt> (one might
|
||||
allocate one more element instead to simplify converting legacy
|
||||
code). Since <tt>ffi.new()</tt> zero-fills the array by default, we
|
||||
only need to set the green and the alpha fields.
|
||||
<span style="color:#4040c0;">①</span> First, load the FFI
|
||||
library and declare the low-level data type. Here we choose a
|
||||
<tt>struct</tt> which holds four byte fields, one for each component
|
||||
of a 4x8 bit RGBA pixel.
|
||||
</p>
|
||||
<p>
|
||||
The calls to <tt>math.floor()</tt> can be omitted here, because
|
||||
floating-point numbers are already truncated towards zero when
|
||||
converting them to an integer. This happens implicitly when the number
|
||||
is stored in the fields of each pixel.
|
||||
<span style="color:#4040c0;">②</span> Creating the data
|
||||
structure with <tt>ffi.new()</tt> is straightforward — the
|
||||
<tt>'?'</tt> is a placeholder for the number of elements of a
|
||||
variable-length array.
|
||||
</p>
|
||||
<p>
|
||||
<span style="color:#4040c0;">③</span> C arrays are
|
||||
zero-based, so the indexes have to run from <tt>0</tt> to
|
||||
<tt>n-1</tt>. One might want to allocate one more element instead to
|
||||
simplify converting legacy code.
|
||||
</p>
|
||||
<p>
|
||||
<span style="color:#4040c0;">④</span> Since <tt>ffi.new()</tt>
|
||||
zero-fills the array by default, we only need to set the green and the
|
||||
alpha fields.
|
||||
</p>
|
||||
<p>
|
||||
<span style="color:#4040c0;">⑤</span> The calls to
|
||||
<tt>math.floor()</tt> can be omitted here, because floating-point
|
||||
numbers are already truncated towards zero when converting them to an
|
||||
integer. This happens implicitly when the number is stored in the
|
||||
fields of each pixel.
|
||||
</p>
|
||||
<p>
|
||||
Now let's have a look at the impact of the changes: first, memory
|
||||
|
||||
Reference in New Issue
Block a user