Foreign Function Interface for Python calling C code.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
C memory allocation, deallocation, garbage collection, and address operations. CFFI provides automatic memory management with options for custom allocators and manual control.
Allocates C data structures with automatic garbage collection and optional initialization.
def new(self, cdecl, init=None):
"""
Allocate C data according to the specified type.
Parameters:
- cdecl (str): C type declaration (pointer or array)
- init: Optional initializer value
Returns:
CData object with automatic memory management
"""Usage Examples:
# Allocate single values
p_int = ffi.new("int *")
p_int[0] = 42
# Allocate with initialization
p_initialized = ffi.new("int *", 100)
# Allocate arrays
arr = ffi.new("int[10]") # Fixed size array
dyn_arr = ffi.new("int[]", 5) # Dynamic array with 5 elements
# Initialize arrays
data = ffi.new("int[]", [1, 2, 3, 4, 5])
# Allocate structures
ffi.cdef("struct point { int x, y; };")
point = ffi.new("struct point *")
point.x = 10
point.y = 20
# Initialize structures
point_init = ffi.new("struct point *", {"x": 10, "y": 20})Creates custom memory allocators with user-defined allocation and deallocation functions.
def new_allocator(self, alloc=None, free=None, should_clear_after_alloc=True):
"""
Create custom allocator function.
Parameters:
- alloc: Custom allocation function (takes size, returns pointer)
- free: Custom deallocation function (takes pointer)
- should_clear_after_alloc (bool): Whether to zero-initialize memory
Returns:
Allocator function compatible with new() interface
"""Usage Example:
# Create custom allocator
def my_alloc(size):
print(f"Allocating {size} bytes")
return ffi.cast("void *", ffi.new("char[]", size))
def my_free(ptr):
print("Freeing memory")
# Memory automatically freed by CFFI
allocator = ffi.new_allocator(my_alloc, my_free)
# Use custom allocator
data = allocator("int[100]")Converts between different C types and Python objects.
def cast(self, cdecl, source):
"""
Cast source to the specified C type.
Parameters:
- cdecl (str): Target C type declaration
- source: Source value (CData, int, pointer, etc.)
Returns:
CData object of the specified type
"""Usage Examples:
# Cast integers to pointers
ptr = ffi.cast("void *", 0x12345678)
# Cast between pointer types
int_ptr = ffi.new("int *", 42)
void_ptr = ffi.cast("void *", int_ptr)
back_to_int = ffi.cast("int *", void_ptr)
# Cast arrays to pointers
arr = ffi.new("int[5]", [1, 2, 3, 4, 5])
ptr = ffi.cast("int *", arr)
# Cast to different integer types
value = ffi.cast("unsigned char", 256) # Results in 0 (overflow)Gets the address of C data objects and structure fields.
def addressof(self, cdata, *fields_or_indexes):
"""
Get address of C data or field within structure/array.
Parameters:
- cdata: C data object
- *fields_or_indexes: Field names or array indexes for nested access
Returns:
Pointer to the specified location
"""Usage Examples:
# Get address of simple data
x = ffi.new("int *", 42)
addr = ffi.addressof(x[0])
# Get address of structure fields
ffi.cdef("struct point { int x, y; };")
point = ffi.new("struct point *")
x_addr = ffi.addressof(point, "x")
y_addr = ffi.addressof(point, "y")
# Get address of array elements
arr = ffi.new("int[10]")
element_addr = ffi.addressof(arr, 5)
# Nested structure access
ffi.cdef("""
struct inner { int value; };
struct outer { struct inner data[5]; };
""")
outer = ffi.new("struct outer *")
inner_addr = ffi.addressof(outer, "data", 2, "value")Attaches custom destructors to C data objects for cleanup when garbage collected.
def gc(self, cdata, destructor, size=0):
"""
Attach destructor to C data object.
Parameters:
- cdata: C data object
- destructor: Function to call on garbage collection
- size (int): Estimated size for GC scheduling
Returns:
New CData object with attached destructor
"""Usage Example:
def cleanup_func(ptr):
print("Cleaning up resource")
# Perform cleanup operations
# Allocate resource with cleanup
resource = ffi.new("void **")
managed_resource = ffi.gc(resource, cleanup_func)def process_data():
# Memory automatically freed when function exits
buffer = ffi.new("char[1024]")
# Use buffer...
return ffi.string(buffer) # Safe: string is copiedclass DataProcessor:
def __init__(self):
# Keep reference to prevent garbage collection
self.buffer = ffi.new("char[4096]")
self.processed = ffi.gc(self.buffer, self._cleanup)
def _cleanup(self, ptr):
print("Buffer cleaned up")ffi.cdef("""
void* create_object(int size);
void destroy_object(void* obj);
""")
lib = ffi.dlopen("mylib.so")
# Create object managed by C library
obj = lib.create_object(1024)
# Attach cleanup function
managed_obj = ffi.gc(obj, lib.destroy_object)# WRONG: pointer becomes invalid
def get_pointer():
data = ffi.new("int *", 42)
return ffi.addressof(data[0]) # Danger: data may be freed
# CORRECT: return the data object itself
def get_data():
data = ffi.new("int *", 42)
return data # Safe: data stays alive# Share memory between Python and C
source = bytearray(b"Hello, World!")
c_buffer = ffi.from_buffer("char[]", source)
# Modifications to c_buffer affect source
c_buffer[0] = ord('h')
print(source) # b"hello, World!"# CFFI doesn't check array bounds - be careful!
arr = ffi.new("int[5]")
# arr[10] = 42 # DANGER: out of bounds access
# Safe pattern: check bounds manually
def safe_set(arr, index, value, size):
if 0 <= index < size:
arr[index] = value
else:
raise IndexError("Array index out of range")Install with Tessl CLI
npx tessl i tessl/pypi-cffi