[pypy-commit] cffi default: A second pass though the doc, completing and expanding parts.
arigo
noreply at buildbot.pypy.org
Thu Jun 14 22:39:49 CEST 2012
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r354:60b3d8bad9a6
Date: 2012-06-14 22:39 +0200
http://bitbucket.org/cffi/cffi/changeset/60b3d8bad9a6/
Log: A second pass though the doc, completing and expanding parts.
diff --git a/doc/source/index.rst b/doc/source/index.rst
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -44,17 +44,17 @@
Requirements:
- * Python 2.6 or 2.7
+* Python 2.6 or 2.7
- * pycparser 2.06: http://code.google.com/p/pycparser/
+* pycparser 2.06: http://code.google.com/p/pycparser/
Installation as usual:
- * ``python setup.py install``
+* ``python setup.py install``
- * or you can directly import and use ``cffi``, but if you don't
- compile the ``_ffi_backend`` extension module, it will fall back
- to using internally ``ctypes`` (slower).
+* or you can directly import and use ``cffi``, but if you don't
+ compile the ``_ffi_backend`` extension module, it will fall back
+ to using internally ``ctypes`` (slower).
Examples
@@ -177,7 +177,7 @@
``ffi.cdef(source)`` parses the given C source. This should be done
first. It registers all the functions, types, and global variables in
-the C source. The types can be used immediately in 'ffi.new()' and
+the C source. The types can be used immediately in ``ffi.new()`` and
other functions. Before you can access the functions and global
variables, you need to give ``ffi`` another piece of information: where
they actually come from (which you do with either ``ffi.dlopen()`` or
@@ -188,16 +188,16 @@
piece of declarations extracted from a man page. The only things it
can assume to exist are the standard types:
- * char, short, int, long, long long (both signed and unsigned)
+* char, short, int, long, long long (both signed and unsigned)
- * float, double
+* float, double
- * intN_t, uintN_t (for N=8,16,32,64), intptr_t, uintptr_t, ptrdiff_t,
- size_t, ssize_t
+* intN_t, uintN_t (for N=8,16,32,64), intptr_t, uintptr_t, ptrdiff_t,
+ size_t, ssize_t
-As we will see on `the verification step`_ below, the declarations
-can also contain ``...`` at various places as placeholders that are
-completed only by during a call to ``verify()``.
+As we will see on `the verification step`_ below, the declarations can
+also contain ``...`` at various places; there are placeholders that will
+be completed by a call to ``verify()``.
Loading libraries
@@ -225,16 +225,17 @@
types exist in the ``ffi`` instance independently of library objects.
This is due to the C model: the types you declare in C are not tied to a
particular library, as long as you ``#include`` their headers; but you
-cannot call functions from a library without linking it in your program.
+cannot call functions from a library without linking it in your program,
+as ``dlopen()`` does dynamically in C.
The verification step
---------------------
-``ffi.verify(source, ...)``: verifies that the current ffi signatures
+``ffi.verify(source, **kwargs)``: verifies that the current ffi signatures
compile on this machine, and return a dynamic library object. The
dynamic library can be used to call functions and access global
-variables declared by a previous 'ffi.cdef()'. The library is compiled
+variables declared by a previous ``ffi.cdef()``. The library is compiled
by the C compiler: it gives you C-level API compatibility (including
calling macros, as long as you declared them as functions in
``ffi.cdef()``). This differs from ``ffi.dlopen()``, which requires
@@ -248,14 +249,14 @@
The arguments to ``ffi.verify()`` are:
- * ``source``: C code that is pasted verbatim in the generated code (it
+* ``source``: C code that is pasted verbatim in the generated code (it
is *not* parsed internally). It should contain at least the
necessary ``#include``. It can also contain the complete
implementation of some functions declared in ``cdef()``; this is
useful if you really need to write a piece of C code, e.g. to access
some advanced macros.
- * ``include_dirs``, ``define_macros``, ``undef_macros``, ``libraries``,
+* ``include_dirs``, ``define_macros``, ``undef_macros``, ``libraries``,
``library_dirs``, ``extra_objects``, ``extra_compile_args``,
``extra_link_args`` (keyword arguments): these are used when
compiling the C code, and are passed directly to distutils_.
@@ -264,35 +265,35 @@
On the plus side, this solution gives more "C-like" flexibility:
- * functions taking or returning integer or float-point arguments can be
+* functions taking or returning integer or float-point arguments can be
misdeclared: if e.g. a function is declared by ``cdef()`` as taking a
``int``, but actually takes a ``long``, then the C compiler handles the
difference.
- * other arguments are checked: you get a compilation warning or error
+* other arguments are checked: you get a compilation warning or error
if you pass a ``int *`` argument to a function expecting a ``long *``.
Moreover, you can use ``...`` in the following places in the ``cdef()``
for leaving details unspecified (filled in by the C compiler):
- * structure declarations: any ``struct`` that ends with ``...;`` is
- partial. It will be completed by the compiler. (You can only access
- fields that you declared; the compiler can only consider the missing
- fields as padding.) Any ``struct`` declaration without ``...;`` is
- assumed to be exact, but this is checked: you get a
- ``VerificationError`` if it is not.
+* structure declarations: any ``struct`` that ends with "``...;``" is
+ partial. It will be completed by the compiler. (But note that you
+ can only access fields that you declared.) Any ``struct``
+ declaration without ``...;`` is assumed to be exact, and this is
+ checked: you get a ``VerificationError`` if it is not.
- * unknown types: the syntax ``typedef ... foo_t;`` declares the type
+* unknown types: the syntax "``typedef ... foo_t;``" declares the type
``foo_t`` as opaque.
- * array lengths: when used as structure fields, arrays can have an
- unspecified length, as in ``int n[];``. The length is completed
+* array lengths: when used as structure fields, arrays can have an
+ unspecified length, as in "``int n[];``". The length is completed
by the C compiler.
- * enums: in ``enum foo { A, B, C, ... };``, the enumerated values are
- not necessarily in order; the C compiler will reorder them as needed
- and skip any unmentioned value. Like with structs, an ``enum`` that
- does not end in ``...`` is assumed to be exact, and this is checked.
+* enums: in "``enum foo { A, B, C, ... };``" (with a trailing ``...``),
+ the enumerated values are not necessarily in order; the C compiler
+ will reorder them as needed and skip any unmentioned value. Like
+ with structs, an ``enum`` that does not end in ``...`` is assumed to
+ be exact, and this is checked.
Working with pointers, structures and arrays
@@ -304,20 +305,28 @@
map to small integers, use either ``signed char`` or ``unsigned char``.)
Pointers, structures and arrays are more complex: they don't have an
-obvious Python equivalent. They correspond to objects of type
+obvious Python equivalent. Thus, they correspond to objects of type
``cdata``, which are printed for example as ``<cdata 'struct foo_s *'>``.
``ffi.new(ctype [, initializer])``: this function builds a new cdata
object of the given ``ctype``. The ctype is usually some constant
string describing the C type. This is similar to a malloc: it allocates
the memory needed to store an object of the given C type, and returns a
-pointer to it. Unlike C, the returned pointer object has *ownership* on
-the allocated memory: when this exact object is garbage-collected, then
-the memory is freed. If you store a pointer to the memory somewhere
-else, then make sure you also keep the object alive for as long as needed.
+pointer to it. The memory is initially filled with zeros. An
+initializer can be given too, as described later.
-The memory is initially filled with zeros. An initializer can be given
-too, as described later.
+Example::
+
+ >>> ffi.new("int")
+ <cdata 'int *' owning 4 bytes>
+ >>> ffi.new("int[10]")
+ <cdata 'int[10]' owning 40 bytes>
+
+Unlike C, the returned pointer object has *ownership* on the allocated
+memory: when this exact object is garbage-collected, then the memory is
+freed. If, at the level of C, you store a pointer to the memory
+somewhere else, then make sure you also keep the object alive for as
+long as needed.
The cdata objects support mostly the same operations as in C: you can
read or write from pointers, arrays and structures. Dereferencing a
@@ -326,6 +335,9 @@
(which is also valid C). Additionally, the ``p->x`` syntax in C becomes
``p.x`` in Python. And instead of ``NULL`` you use None.
+There is no equivalent to the ``&`` operator in C (because it would not
+fit nicely in the model, and it does not seem to be needed here).
+
Any operation that would in C return a pointer or array or struct type
gives you a new cdata object. Unlike the "original" one, these new
cdata objects don't have ownership: they are merely references to
@@ -367,16 +379,23 @@
Like C, arrays of chars can also be initialized from a string, in
which case a terminating null character is appended implicitly::
- >>> x = ffi.new("char[]", "hello" + chr(0) + "world")
+ >>> x = ffi.new("char[]", "hello")
>>> x
- <cdata 'char[]' owning 12 bytes>
+ <cdata 'char[]' owning 6 bytes>
>>> len(x) # the actual size of the array
- 12
+ 6
+ >>> x[5] # the last item in the array
+ '\x00'
+ >>> x[0] = 'H' # change the first item
>>> str(x) # interpret 'x' as a regular null-terminated string
- 'hello'
+ 'Hello'
-The C array types can have their length unspecified in C types, as long
-as their length can be derived from the initializer, like in C::
+Note that unlike Python lists or tuples, but like C, you cannot index in
+a C array using negative numbers.
+
+More generally, the C array types can have their length unspecified in C
+types, as long as their length can be derived from the initializer, like
+in C::
static int globvar[] = { 1, 2, 3, 4 }; // C syntax
globvar = ffi.new("int[]", [1, 2, 3, 4]) # CFFI equivalent
@@ -389,11 +408,32 @@
globvar = ffi.new("int[]", 1000) # CFFI 2nd equivalent
This is useful if the length is not actually a constant, to avoid doing
-things like ``ffi.new("int[%d]" % x)``, which is not recommended:
+things like ``ffi.new("int[%d]"%x)``. Indeed, this is not recommended:
``ffi`` normally caches the string ``"int[]"`` to not need to re-parse
it all the time.
+Variadic function calls
+-----------------------
+
+Variadic functions in C (which end with "``...``" as their last
+argument) can be declared and called normally, with the exception that
+all the arguments passed in the variable part *must* be cdata objects,
+or possibly None for ``NULL``. This is because it would not be possible
+to guess, if you wrote this::
+
+ C.printf("hello, %d\n", 42)
+
+that you really meant the 42 to be passed as a C ``int``, and not a
+``long`` or ``long long``. The same issue occurs with ``float`` versus
+``double``. So you have to force cdata objects of the C type you want,
+if necessary with ``ffi.cast()``::
+
+ C.printf("hello, %d\n", ffi.cast("int", 42))
+ C.printf("hello, %ld\n", ffi.cast("long", 42))
+ C.printf("hello, %f\n", ffi.cast("double", 42))
+
+
Callbacks
---------
@@ -408,31 +448,45 @@
<cdata 'int(*)(int, int)' calling <function myfunc at 0xf757bbc4>>
Warning: like ffi.new(), ffi.callback() returns a cdata that has
-ownership of its C data. This means that the callback can only be
-invoked as long as this cdata object is alive. If you store this
-callback somewhere, then make sure you also keep this object alive for
-as long as the callback may be invoked.
+ownership of its C data. (In this case, the necessary C data contains
+the libffi data structures to do a callback.) This means that the
+callback can only be invoked as long as this cdata object is alive. If
+you store this callback somewhere, then make sure you also keep this
+object alive for as long as the callback may be invoked. (If you want
+the callback to remain valid forever, store the object in a fresh global
+variable somewhere.)
+
+Note that callbacks of a variadic function type are not supported.
Miscellaneous
-------------
``ffi.string(pointer, length)``: return a Python string containing all
-the data at the given location with the given size. The pointer must
-be a cdata of type ``void *`` or ``char *``.
+the data at the given location with the given size. The pointer must be
+a cdata of type ``void *`` or ``char *``. Null characters are not
+considered special here: the resulting string always has the given
+``length``, possibly with embedded null characters.
-``ffi.typeof("C type")``: return an object of type ``ctype``
-corresponding to the parsed string. Usually you don't need to call this
-function: any place that accepts a C type can receive either a string or
-a pre-parsed ``ctype`` object (and does caching of the string, so there
-is no real performance advantage).
+``ffi.typeof("C type" or cdata object)``: return an object of type
+``<ctype>`` corresponding to the parsed string, or to the C type of the
+cdata instance. Usually you don't need to call this function or to
+explicitly manipulate ``<ctype>`` objects in your code: any place that
+accepts a C type can receive either a string or a pre-parsed ``ctype``
+object (and because of caching of the string, there is no real
+performance difference). It can still be useful in writing typechecks,
+e.g.::
+
+ def myfunction(ptr):
+ assert ffi.typeof(ptr) is ffi.typeof("foo_t*")
+ ...
``ffi.sizeof("C type" or cdata object)``: return the size of the
argument in bytes. The argument can be either a C type, or a cdata object,
like in the equivalent ``sizeof`` operator in C.
``ffi.alignof("C type")``: return the alignment of the C type.
-Corresponds to e.g. the ``__alignof__`` operator in GCC.
+Corresponds to the ``__alignof__`` operator in GCC.
``ffi.offsetof("C struct type", "fieldname")``: return the offset within
the struct of the given field. Corresponds to ``offsetof()`` in C.
More information about the pypy-commit
mailing list