CookbookTop, Main, Index
While using CFFI to wrap a few ad-hoc functions is fairly straightforward, wrapping a large API into a complete package can be more involved as decisions how C types are translated to script level annotations. This page provides some recipes for mapping C declarations to CFFI declarations depending on the declaration context (parameter, struct field etc.).
Defining a functionTop, Main, Index
A function definition consists of three components.
Sections below detail definition of each.
Calling conventionTop, Main, Index
Check the header file or documentation of the function for the expected calling convention. Generally, this is only an issue if the application supports the 32-bit Windows platform. Note the function calling convention may be defined through a macro such as WINAPI
etc. Most Windows OS API's are defined using the stdcall convention. The default C language calling convention is either unspecified or _cdecl
in C header files. Most third party API's are defined using this convention. CFFI does not support any calling convention other than these two.
- Define using
stdcall
if the function is defined on 32-bit Windows using__stdcall
or its equivalent. Note on other platforms, including 64-bit Windows, this is treated as equivalent tofunction
- Define using
function
otherwise after ensuring it does not use some other esoteric platform-specific convention (rare).
Examples
C
CFFI
Note WINAPI
in the Windows SDK headers maps to __stdcall
.
Return type declarationTop, Main, Index
Void returnsTop, Main, Index
The void
return type does not permit any annotations.
Examples
C
CFFI
Integer returnsTop, Main, Index
- If the returned values are constrained to a set and a symbolic representation is preferred, optionally add the
enum
attribute with the enumeration defined as a literal or separately through the ::cffi::enum command. - If a symbolic representation is preferred as above and the value is actually a bit mask, optionally add the
bitmask
attribute to have the value returned as a list of symbols from the enumeration. - If return values may indicate error conditions, add an error checking annotation like
zero
,nonzero
etc. - If a error checking annotation is added and additional detail is available from the system, add
lasterror
,winerror
orerrno
as appropriate. If error information is available through some other API, add theonerror
handler. This may also be used to filter errors or convert error conditions to success. - If error conditions are not detectable from the return value but the function expects caller to check
errno
orGetLastError()
after the call returns, add thesaveerrors
annotation instead of the above. Then call ::cffi::savederrors to retrieve or check for errors. - If the return value is simply a boolean indicating success or failure, include the
discard
annotation to have an empty string returned on success. Note this does not affect exceptions raised on error.
Examples
C
CFFI
A basic definition assuming LIBC
is the library wrapper object:
A more complete definition:
Floating point returnsTop, Main, Index
Floating point types float
and double
do not permit any annotations on return type declarations.
Examples
C
CFFI
Pointer returnsTop, Main, Index
Pointer return values may be dealt with at the script level either as raw pointers or as implicitly dereferenced values.
- Declare the function as returning a raw pointer if the returned pointers point to resources that have to be freeing at a later point. If typed as implicitly dereferenced values, the raw pointer will not be available for freeing.
- Declare the function as returning an implicitly dereferenced value if the returned pointers point to some internal or static storage that does not need to be freed. An example is the
strerror
C runtime library function. Note that implicitly dereferenced types are a convenience; they may be typed as raw pointers instead while the reverse will likely produce memory leaks.
The type declarations for raw and implicitly dereferenced pointers are separately described below.
Raw pointers
- The
TAG
is optional but recommended wherever possible for additional tag-based type checks. If the pointer's target type is a struct, it is is recommended, but not mandatory, that the tag used be the name of the struct instance command. This makes it convenient to access the referenced memory using the struct methods. - By default, pointers returned from functions are marked as safe pointers. This is appropriate for unique pointers that are returned for allocated resources and are only valid until they are deallocated through a corresponding free function. A variation is when the pointer returned is not unique as is the case for reference counted resources. In this case the pointer should be annotated as
counted
. A special case of this is when the returned pointer is static or a "pseudo-pointer" that is always valid in which case thepinned
annotation should be applied.
For cases where none of the above apply, for example there is no clear transfer of ownership or freeing, or pointers are internal to the API, there are two choices. First, it can be defaulted as a safe pointer. In this case, since there is no free function, the ::cffi::pointer dispose command must be called at the appropriate time by the application to unregister the pointer. Alternatively, the unsafe
annotation can be added to the declaration. In this case, there is no need to unregister the pointer but it can only be used in places (arguments and struct fields) that also have the unsafe
annotation. For more details on pointer management and safety, see Pointer safety.
- Irrespective of the pointer safety annotations, NULL pointers returned from functions will by default raise a generic Pointer is NULL exception. As for integer return values, if additional information is available from the system or API, the type can be annoted with
lasterror
,errno
oronerror
. On the other hand, if a NULL pointer is a valid return value, thenullok
annotation will suppress the exception and return a NULL pointer at the script level. - If error conditions are not detectable from the return value but the function expects caller to check
errno
orGetLastError()
after the call returns, add thesaveerrors
annotation instead of the above. Then call ::cffi::savederrors to retrieve or check for errors.
Examples
C
CFFI
The unsafe
and counted
annotations on git_tree_entry_byname
arise from the libgit2 API. The returned pointer is internal to libgit2 and hence marked as unsafe while git_tree
structs are reference counted.
Implicitly dereferenced pointers
Raw pointers at script level, while as versatile as their C counterparts, are not as convenient to use as plain old values. Additional steps are needed to access the memory as script level values. Declaring pointer return types as implicitly dereferenced obviates the need for this additional step. As stated earlier, implicit dereferencing should only be done when there is no need for the pointer value itself for freeing later.
For types other than pointers to character (or unicode) strings, the CFFI declaration has the form
where TYPE
may be one of the numeric types or a STRUCT
. The byref
annotation on the return type declaration denotes that the function return value is nominally a pointer that references the true function result.
Examples
C
CFFI
A call to the git_tree_oid
function will then return the git_oid
struct (assumed defined previously with ::cffi::Struct) in its script level dictionary form. The actual C level pointer is not accessible but not needed as it is internal to the git_tree
and not to be freed or manipulated.
As for raw pointers, a null pointer return will raise an exception by default. The nullok
annotation may suppress the exception in the case that TYPE
is a struct with defaults defined for all fields (possibly with the -clear
option). In that the dictionary corresponding to a struct value with all fields defaulted is returned. For all other types and structs with at least one field without a default, an exception is raised irrespective of nullok
.
For C pointers typed as char *
which return pointers to character strings, the implicit dereference syntax is
The byref
is not present because string
, unistring
and winstring
are already implicit pointers, (string byref
would correspond to char **
, not char *
). An optional nullok
annotation will cause a NULL pointer return to be mapped to the empty string instead of generating an exception.
Note that if STRING
is string
, an encoding identifier may be optionally attached, e.g. string.utf-8
.
The multisz
may only be used when STRING
is winstring
. The value is interpreted as holding a Windows MULTI_SZ
string type and returned as a list.
Examples
C
CFFI
Note the definition of strstr
to return an empty string if the needle is not found instead of raising an exception.
Struct returnsTop, Main, Index
A struct function return type does not permit any annotations. STRUCT
must be a previously defined ::Struct. Returning a struct by value is rarely seen in C API's.
Examples
C
CFFI
Parameter declarationTop, Main, Index
Parameters to a C function may be used to pass values to the function (input parameters), retrieve values from the function (output parameters), or (input-output parameters).
Scalar values and structs that are passed by value are always input parameters. Input parameters may also be passed by reference via a pointer, generally with a const
attribute to indicate the function does not modify the referenced value.
Output and input-output parameters are always passed to C function as pointers to a location where the value is stored. At the script level the argument is the name of the variable where the value is stored and not the value itself.
Integer parametersTop, Main, Index
Integer input parameters
- The
in
annotation is optional because it is the default if none ofout
,retval
orinout
annotations is present. - The
byref
annotation should be specified iff the value is being passed by reference, i.e. the function parameter is a pointer to the value (e.g.int *
at the C level). This is very rare for integer values that are input only. In either case, whether thebyref
parameter is present or not, the value at script level is still specified directly and not through a variable. - Add the
enum
annotation to pass enumeration symbolic values for readability purposes. Note integer values will still be accepted. - If the parameter holds a bit mask, add the
bitmask
annotation which allows the argument to be a list of integers which will be bitwise OR-ed to construct the value passed to the function. May be combined withenum
to pass a list of symbols. - The
default
annotation may be used to supply a default value to be passed if no argument is supplied for the parameter when the function is invoked. All succeeding parameter in the parameter list must also have default annotations. - Error handling annotations like
errno
may be present but are ignored. This is to permit the same aliases to be used in both return and parameter declarations.
Examples
C
CFFI
Output and input-output integer parameters
- Output and in-out parameters in C are always passed as pointers to the location where output value is to be stored. Thus
out
andinout
always implybyref
which is redundant and need not be specified. - The script level argument corresponding to
out
andinout
parameters are the name of the variable to which the output value is to be assigned. Forinout
parameters this must exist at the time of function call and hold a valid value for the type. - Use the
retval
annotation for output parameters where you want the output parameter value from the function to be returned as the function result in lieu of the actual function return value. See Output parameters as function result. - Add the
enum
annotation if output values are to be mapped to symbolic names for readability. Further, if the values returned are actually bitmasks, addbitmask
to have the returned value transformed to a list of symbolic names. - If the function return value is subject to error checks (for example null pointer checks) and fails the checks, output values are not stored in variables as they may hold garbage values. The
storealways
annotation indicates the output value is valid regardless of function failure. Thestoreonerror
annotation indicates the output value is valid only on function failure (for example an error code). See Errors and output parameters. - Error handling annotations like
errno
may be present but are ignored. This is to permit the same aliases to be used in both return and parameter declarations. - Add the
nullifempty
annotation forout
andinout
function parameters that are allow NULL to be passed as the argument when no output value is of interest. When the function wrapper is invoked, pass the empty string as the output variable name.
Examples
C
CFFI
Floating point parametersTop, Main, Index
Floating point input parameters
- The
in
annotation is optional because it is the default if none ofout
,retval
orinout
annotations is present. - The
byref
annotation should be specified iff the value is being passed by reference, i.e. the function parameter is a pointer to the value (e.g.double *
at the C level). This is very rare for integer values that are input only. In either case, whether thebyref
parameter is present or not, the value at script level is still specified directly and not through a variable. - The
default
annotation may be used to supply a default value to be passed if no argument is supplied for the parameter when the function is invoked. All succeeding parameter in the parameter list must also have default annotations.
Examples
C
CFFI
Out and in-out floating point parameters
- Output and in-out parameters in C are always passed as pointers to the location where output value is to be stored. Thus
out
andinout
always implybyref
which is redundant and need not be specified. - The script level argument corresponding to
out
andinout
parameters are the name of the variable to which the output value is to be assigned. Forinout
parameters this must exist at the time of function call and hold a valid value for the type. - Use the
retval
annotation for output parameters where you want the output parameter value from the function to be returned as the function result in lieu of the actual function return value. See Output parameters as function result. - If the function return value is subject to error checks (for example null pointer checks) and fails the checks, output values are not stored in variables as they may hold garbage values. The
storealways
annotation indicates the output value is valid regardless of function failure. Thestoreonerror
annotation indicates the output value is valid only on function failure (for example an error code). See Errors and output parameters. - Add the
nullifempty
annotation forout
andinout
function parameters that are allow NULL to be passed as the argument when no output value is of interest. When the function wrapper is invoked, pass the empty string as the output variable name.
Pointer parametersTop, Main, Index
As for return values, pointer parameters to C functions can be dealt with either as raw pointers or as implicitly dereferenced values.
In general, pointers that are only used in the C API to pass arguments by reference, for example to pass large or non-scalar input values (as for structs and arrays) or receive output values, can be declared as implicitly dereferenced. The CFFI declarations for these is described in other sections with use of the byref
and out
annotations.
This section deals only with raw pointers where the pointer values are directly visible at the script level. This is necessary when the pointers reference resources that need to freed, or in more complex structures in memory with multiple indirections etc.
Raw pointer input parameters
- The
TAG
is optional but recommended wherever possible for additional tag-based type checks. If the pointer's target type is a struct, it is is recommended, but not mandatory, that the tag used be the name of the struct instance command. This makes it convenient to access the referenced memory using the struct methods. - The
in
annotation is optional because it is the default if none ofout
,retval
orinout
annotations is present. - The
byref
annotation should be specified iff the pointer is being passed by reference, i.e. the function parameter is a pointer to a pointer. Generally, input parameters passed by reference will haveconst
in the C parameter declaration. - By default, pointers passed into functions are expected to be registered as safe pointers. They may be alternatively be annotated with
counted
, pinned which also get the default handling in case of input parameters. If the pointer is not expected to have been registered, theunsafe
annotatio should be used. For more details on pointer management and safety, see Pointer safety. - When a C function releases the resource associated with a registered pointer (safe or counted), the pointer should be unregistered. The
dispose
annotation should be placed on the parameter annotation to convey to CFFI that the pointer should be unregistered. Thedisposeonsuccess
annotation is similar except that the pointer is unregistered only in the case the function returns successfully. The annotation has no effect on pinned pointers and should not be used in conjunction with theunsafe
annotation. For more details on pointer management and safety, see Pointer safety. - CFFI assumes by default that functions do not accept NULL pointers and will raise an exception if an attempt is made to pass one. The
nullok
annotation indicates that the function allows for the pointer to be NULL. - The
default
annotation may be used to supply a default value to be passed if no argument is supplied for the parameter when the function is invoked. All succeeding parameter in the parameter list must also have default annotations.
Examples
C
CFFI
Raw pointer out and in-out parameters
- Output parameters in C are always passed as pointers to the location where output value is to be stored. Thus
out
always impliesbyref
which is redundant and need not be specified. - The script level argument corresponding to an
out
parameter is the name of the variable to which the output value is to be assigned. - Use the
retval
annotation for output parameters where you want the output parameter pointer value from the function to be returned as the function result in lieu of the actual function return value. See Output parameters as function result. - By default, pointers returned in out and in-out parameters are registered as safe pointers. They may be alternatively be annotated with
counted
orpinned
to be registered as counted or pinned pointers orunsafe
if they are not to be registered at all. For more details on pointer management and safety, see Pointer safety. - When a C function releases the resource associated with a registered pointer (safe or counted), the pointer should be unregistered. The
dispose
annotation should be placed on the parameter annotation to convey to CFFI that the pointer should be unregistered. The annotation may also be applied to pinned pointers but has no effect. Thedisposeonsuccess
annotation is similar except that the pointer is unregistered only in the case the function returns successfully. Thedispose
anddisposeonsuccess
annotations is not valid with theout
orretval
annotations. For more details on pointer management and safety, see Pointer safety. - The
nullok
annotation indicates that pointers passed in and out of the function can be NULL. Without the annotation, an exception is raised if the pointer stored on output is NULL or in the case ofinout
the pointer passed in is NULL. - Add the
nullifempty
annotation forout
andinout
function parameters that are allow NULL to be passed as the argument when no output value is of interest. When the function wrapper is invoked, pass the empty string as the output variable name. - The
default
annotation may be used to supply a default pointer value to be passed if no argument is supplied for the parameter when the function is invoked. All succeeding parameter in the parameter list must also have default annotations. This annotation cannot be used without
andretval
annotations. - If the function return value is subject to error checks (for example null pointer checks) and fails the checks, output values are not stored in variables as they may hold garbage values. The
storealways
annotation indicates the output value is valid regardless of function failure. Thestoreonerror
annotation indicates the output value is valid only on function failure (for example an error code). See Errors and output parameters.
Examples
C
CFFI
In the libgit2
example, out
is annotated as counted
because git_repository
is a reference counted opaque structure. The retval
annotation is added to have CFFI return the output parameter value as the result of the function.
In the Win32 example, the returned pointer from ConvertSidToStringSidW
needs to be freed with LocalFree
and hence needs to be declared as a raw pointer. The string can be retrieved from the returned pointer with ::cffi::memory tostring before freeing it.
Struct parametersTop, Main, Index
Struct values are represented as the script level as dictionaries. This requires their definition as described in Structs and Defining structs.
Struct input parameters
- The
in
annotation is optional because it is the default if none ofout
,retval
orinout
annotations is present. - The
byref
annotation should be specified iff the value is being passed by reference, i.e. the function parameter is a pointer to a struct value that is to be passed. Generally, input parameters passed by reference will haveconst
in the C parameter declaration. Irrespective of this annotation, the argument is always a dictionary, not a pointer. - The
default
annotation may be used to supply a default value to be passed if no argument is supplied for the parameter when the function is invoked. All succeeding parameter in the parameter list must also have default annotations. - Some C functions accept a NULL pointer for optional parameters. The
nullifempty
annotation identifies such parameters. In this case, passing an empty dictionary as the script level argument will result in a NULL pointer being passed to the function. This annotation only makes sense in the presence of thebyref
annotation.
Examples
C
CFFI
Output and input-output struct parameters
- Output and in-out parameters in C are always passed as pointers to the location where output value is to be stored. Thus
out
andinout
always implybyref
which is redundant and need not be specified. - The script level argument corresponding to
out
andinout
parameters are the name of the variable to which the output value is to be assigned. Forinout
parameters this must exist at the time of function call and hold a valid value for the type. - Use the
retval
annotation for output parameters where you want the output parameter value from the function to be returned as the function result in lieu of the actual function return value. See Output parameters as function result. - If the function return value is subject to error checks (for example null pointer checks) and fails the checks, output values are not stored in variables as they may hold garbage values. The
storealways
annotation indicates the output value is valid regardless of function failure. Thestoreonerror
annotation indicates the output value is valid only on function failure (for example an error code). See Errors and output parameters. These annotations are rarely applicable to struct output parameters. - Add the
nullifempty
annotation forout
andinout
function parameters that are allow NULL to be passed as the argument when no output value is of interest. When the function wrapper is invoked, pass the empty string as the output variable name.
Examples
C
CFFI
String parametersTop, Main, Index
Input string parameters
- C does not have a string type and the
string
,unistring
andwinstring
CFFI types map to pointers to nul terminated character strings:char*
in the case ofstring
,Tcl_UniChar *
in the case ofunistring
andWCHAR *
in the case ofwinstring
. For input parameters, they have theconst
attribute. - The
in
annotation is optional because it is the default if none ofout
,retval
orinout
annotations is present. - For the
string
type an optional encoding may be specified and defaults to the system encoding. If a library API uses a specific encoding (commonly UTF-8), it may be convenient to define a type alias. - The
byref
annotation should be specified iff the value is being passed by reference, i.e. the function parameter is a pointer to the pointer to the character string (double indirection). This is rare for passing character string values that are input only. In either case, whether thebyref
parameter is present or not, the value at script level is still specified directly and not through a variable. - Some C functions accept a NULL pointer for optional parameters. The
nullifempty
annotation identifies such parameters. In this case, passing an empty string as the script level argument will result in a NULL pointer being passed to the function. - The
multisz
may only be used forwinstring
. The passed value is list of strings and is mapped to a WindowsMULTI_SZ
string type.
Examples
C
CFFI
Output and input-output string parameters
Character strings are returned from C functions in one of two ways:
- The C function expects the caller to supply a pointer to an array of characters. The size of this array may be a compile time constant or passed through another parameter to the function. The function then stores the string in this buffer. The C parameter declaration is of the form
char *buf
orchar buf[]
. - The C function expects the caller to pass a pointer to a memory location where it will store the pointer to a string that is either dynamically allocated or an internal static string. The C declaration is of the form
char **ptr_to_buf
reflecting the double indirection.
The two are handled differently in CFFI as described below.
Output character arrays
This is the first case described above where the C function expects a pointer to a character (or Tcl_UniChar
and WCHAR
in the case of unichars
and winchars
) array.
- The script level argument corresponding to
out
andinout
parameters are the name of the variable to which the output value is to be assigned. Forinout
parameters this must exist at the time of function call and hold a valid value for the type. - Use the
retval
annotation for output parameters where you want the output parameter value from the function to be returned as the function result in lieu of the actual function return value. See Output parameters as function result. - The array size
N
in the declaration may either be an integer constant or the name of a integer type parameter in the same function declaration. See Dynamically sized arrays. - If
ENCODING
is not specified, it defaults to the system encoding. - If the function return value is subject to error checks (for example null pointer checks) and fails the checks, output values are not stored in variables as they may hold garbage values. The
storealways
annotation indicates the output value is valid regardless of function failure. Thestoreonerror
annotation indicates the output value is valid only on function failure (for example an error code). See Errors and output parameters. - The
multisz
may only be used forwinchars
. The output is interpreted as holding a WindowsMULTI_SZ
string type and stored as a Tcl list. - Add the
nullifempty
annotation forout
andinout
function parameters that are allow NULL to be passed as the argument when no output value is of interest. When the function wrapper is invoked, pass the empty string as the output variable name.
Examples
C
CFFI
Output pointers to strings
The second case is when the C function parameter is a pointer to pointer to a character string (char **
).
How this is best handled depends on whether the returned pointer needs to be available at the script level as a raw pointer, possibly for later freeing. See Pointer returns for a more detailed discussion about raw pointers versus implicit dereferencing. If this is the case, see Raw pointer out and in-out parameters for appropriate declarations.
If retention of the raw pointer is not required (for example, pointer to static storage), then its most convenient to implicitly declare it as an output parameter of
- Output parameters in C are always passed as pointers to the location where output value is to be stored. Thus
out
always impliesbyref
which is redundant and need not be specified. - The script level argument corresponding to an
out
parameter is the name of the variable to which the output value is to be assigned. - Use the
retval
annotation for output parameters where you want the output parameter value from the function to be returned as the function result in lieu of the actual function return value. See Output parameters as function result. - If the function return value is subject to error checks (for example null pointer checks) and fails the checks, output values are not stored in variables as they may hold garbage values. The
storealways
annotation indicates the output value is valid regardless of function failure. Thestoreonerror
annotation indicates the output value is valid only on function failure (for example an error code). See Errors and output parameters. These annotations are rarely applicable to struct output parameters. - The
multisz
annotation may only be used forwinstring
. The pointer stored in the output parameter is interpreted as pointing to a WindowsMULTI_SZ
string type and stored in the Tcl variable as a list.
Binary string parametersTop, Main, Index
Binary strings are similar to strings except that instead of treating pointers at the C level as character strings in Tcl, they treat them as binary strings so there is no character encoding/decoding transformation applied and nul characters have no special treatment.
Binary strings can be typed as binary
or as an array of bytes
. In many cases the two are interchangeable. As a general rule, bytes
is to be prefered when the function expects an array of bytes whose length is passed through another parameter while binary
is more directed when the function does not need any additional information to deduce the size of the passed data.
Input binary string parameters
- The usual corresponding C declarations are
char *
,unsigned char *
andvoid *
. Further, input parameters have theconst
attribute. - The
in
annotation is optional because it is the default if none ofout
,retval
orinout
annotations is present. - The
byref
annotation is only applicable to thebinary
type and should be specified iff the value is being passed by reference, i.e. the function parameter is a pointer to the pointer to the array of bytes string (double indirection). This is rare for passing binary values that are input only. In either case, whether thebyref
parameter is present or not, the value at script level is still specified directly and not through a variable. - Some C functions accept a NULL pointer for optional parameters. The
nullifempty
annotation identifies such parameters. In this case, passing an zero-length binary string as the script level argument will result in a NULL pointer being passed to the function. - The
default
annotation may be used to supply a default value to be passed if no argument is supplied for the parameter when the function is invoked. All succeeding parameter in the parameter list must also have default annotations.
Examples
C
CFFI
Output and input-output binary string parameters
Binary strings are returned from C functions in one of two ways:
- The C function expects the caller to supply a pointer to a memory block interpreted simply as an array of bytes. The size of this memory block may be a compile time constant or passed through another parameter to the function. The function then stores the data in this memory buffer. The C parameter declaration is generally one of
void *
,char *buf
,char buf[]
(or the unsigned variants). - The C function expects the caller to pass a pointer to a memory location where it will store the pointer to a block of memory that is either dynamically allocated or an internal buffer. The C declaration is of the form
char **
,unsigned char **
orvoid **
reflecting the double indirection.
The two are handled differently in CFFI as described below.
Output byte arrays
This is the first case described above where the C function expects a pointer to a byte array.
- The script level argument corresponding to
out
andinout
parameters are the name of the variable to which the output value is to be assigned. Forinout
parameters this must exist at the time of function call and hold a Tcl binary string. - Use the
retval
annotation for output parameters where you want the output parameter value from the function to be returned as the function result in lieu of the actual function return value. See Output parameters as function result. - The array size
N
in the declaration may either be an integer constant or the name of a integer type parameter in the same function declaration. See Dynamically sized arrays. - If the function return value is subject to error checks (for example null pointer checks) and fails the checks, output values are not stored in variables as they may hold garbage values. The
storealways
annotation indicates the output value is valid regardless of function failure. Thestoreonerror
annotation indicates the output value is valid only on function failure (for example an error code). See Errors and output parameters.
The difference between an array declared as bytes[N]
versus schar[N]
or uchars[N]
is that while both might be arrays of char
or unsigned char
at the C level, the former declaration will result in a Tcl binary string at the script level while the latter declarations will result in lists of integers.
Examples
C
CFFI
Output pointers to binary strings
Another way of returning binary data is through a parameter that is a pointer to pointer to the data (char **
etc.). This case has to be handled as raw pointers since, unlike for character strings, there is no way for CFFI to know the size of the data being returned.
Arrays as parametersTop, Main, Index
- Arrays in C are always passed by reference, as a pointer to the first element of the array. CFFI array type declarations therefore are implicitly annotated as
byref
. - The array size in the type declaration may be an integer constant or specified as the name of another parameter. See Dynamically sized array.
- The annotations permitted on an array type declaration are those permitted for the base type. For example, integer array declarations may have the
enum
annotation. - At the script level, arrays are represented as lists except for the special cases of as `chars` or `bytes` where they are character or binary strings.
Defining structsTop, Main, Index
Native C struct values may be dealt with at the script level either as Tcl dictionary values or kept in their native form and accessed through raw pointers. Both methods require the struct to be defined with ::cffi::Struct. In the former case, the fields are accessed using Tcl's dict
command. In the latter case, the ::cffi::Struct accessor methods are used.
Field type declarationsTop, Main, Index
The field type declarations in a struct definition, while similar to function parameter type declarations, differ from them in some respects.
- The
void
andbinary
base types cannot be used in struct fields. - The annotations for each type are differ from those applicable in a parameter context.
Integer fieldsTop, Main, Index
- If the
enum
annotation is present, the field is subject to mapping to symbols from the enumeration. - If the
bitmask
annotation is present, the dictionary element for the field is treated a list of integers that are bitwise OR-ed to form the native field value. - The
default
annotation specifies a default value to be used when constructing a native struct from the dictionary representation if the dictionary does not contain a key for the field. - The
structsize
annotation specifies that the field should be defaulted to the size of the native struct. - Error handling annotations like
errno
may be present but are ignored. This is to permit the same aliases to be used in both function struct definitions.
Floating point fieldsTop, Main, Index
- The
default
annotation specifies a default value to be used when constructing a native struct from the dictionary representation if the dictionary does not contain a key for the field.
Pointer fieldsTop, Main, Index
- The
TAG
is optional but recommended wherever possible for additional tag-based type checks. If the pointer's target type is a struct, it is is recommended, but not mandatory, that the tag used be the name of the struct instance command. This makes it convenient to access the referenced memory using the struct methods. - Pointer fields in a struct are always treated as unsafe even when the
unsafe
annotation is not specified. Thecounted
andpinned
annotations may be present (for sharing a type alias with parameter types) but are ignored. - The
nullok
annotation should be applied to any field that can validly hold a NULL pointer. In the absence of an annotation, an exception is raised if an attempt is made to assign the field in a native struct a NULL pointer value. - Pointer fields that hold pointers to character strings may be alternatively declared as string pointer fields under some restrictions described below.
String pointer fieldsTop, Main, Index
- The
nullifempty
annotation may be used in cases where an empty string at the script level should be stored as a NULL pointer in the struct field. - The
multisz
may only be used forwinstring
. The referenced value is interpreted as holding a WindowsMULTI_SZ
string type and returned at the script level as a list.
As for function parameters, fields that hold pointers to character strings can be more conveniently declared as one of the CFFI string types if the raw pointer is not required for freeing of resources or other purposes. There is a restriction imposed when a struct field is declared as a string type. The struct definition may be used to pass and return parameters from functions but cannot be used with the ::cffi::Struct.new or ::cffi::Struct.allocate methods to allocate a native struct in memory.
Character array fieldsTop, Main, Index
Like string
, unistring
and winstring
, the chars
, unichars
and winchars
CFFI types are character strings at the script level. However, while the former maps to pointers at the C level, chars
, unichars
and winchars
map to char[]
, Tcl_UniChar[]
and WCHAR
arrays.
- The
default
annotation may be used to supply a default value to be stored in the native C struct if the dictionary representation does not have a key matching the field. - The array size
N
must be an positive integer constant and not dynamically sized as is permitted for array parameters. - The
multisz
may only be used forwinchars
. The character array is interpreted as holding a WindowsMULTI_SZ
string type and is a list at the script level.
Byte array fieldsTop, Main, Index
The difference between an array declared as bytes[N]
versus schar[N]
or uchars[N]
is that while both might be arrays of char
or unsigned char
at the C level, the former declaration will result in a Tcl binary string at the script level while the latter declarations will result in lists of integers.
- The
default
annotation may be used to supply a default value to be stored in the native C struct if the dictionary representation does not have a key matching the field. - The array size
N
must be an positive integer constant and not dynamically sized as is permitted for array parameters.
Nested struct fieldsTop, Main, Index
A struct definition may include a field that is declared as another struct.
- A nested
STRUCT
struct may have a default value specified as a dictionary mapping field names ofSTRUCT
to field values. - A nested struct of variable size may only appear as the last field in its parent.
Array fieldsTop, Main, Index
- The array size
N
must be an positive integer constant or the name of another field in the struct which will hold the array size. In the latter case, the array must be the last field in the struct and its element type should not itself be a variable size type. - The annotations permitted on an array type declaration are those permitted for the base type. For example, integer array declarations may have the
enum
annotation. - At the script level, C arrays are represented as lists except for the special cases of as `chars` or `bytes` where they are character or byte arrays.
Defining unionsTop, Main, Index
Definition of unions follows the rules for defined for structs with except that unions may not contain variable sized fields.
Tips and tricksTop, Main, Index
This section to be written
- duplicating structure or function definition
- pointer casting - implicit and explicit
- use raw pointers for large data to avoid copies
- use memory get command to decode native memory in type-specific manner
- use defaults, -clear, structsize for structs
- use help interactively