Foreign Function Interface for Python calling C code.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
C type introspection and manipulation operations. The type system provides complete information about C types, sizes, alignment, and structure layouts.
Gets type information for C declarations and data objects.
def typeof(self, cdecl):
"""
Get the C type of a declaration or data object.
Parameters:
- cdecl (str|CData): C type string or existing CData object
Returns:
CType object representing the C type
"""Usage Examples:
# Get type from string declaration
int_type = ffi.typeof("int")
ptr_type = ffi.typeof("int *")
array_type = ffi.typeof("int[10]")
# Get type from existing data
data = ffi.new("int *", 42)
data_type = ffi.typeof(data) # Returns pointer type
# Function types
ffi.cdef("int add(int a, int b);")
func_type = ffi.typeof("int(*)(int, int)")
# Structure types
ffi.cdef("struct point { int x, y; };")
struct_type = ffi.typeof("struct point")Gets the size in bytes of C types or data objects.
def sizeof(self, cdecl):
"""
Get size in bytes of C type or data object.
Parameters:
- cdecl (str|CData): C type string or CData object
Returns:
int: Size in bytes
"""Usage Examples:
# Basic type sizes
int_size = ffi.sizeof("int") # Usually 4
long_size = ffi.sizeof("long") # Platform dependent
ptr_size = ffi.sizeof("void *") # Usually 8 on 64-bit
# Array sizes
array_size = ffi.sizeof("int[10]") # 40 bytes (10 * 4)
# Structure sizes (including padding)
ffi.cdef("struct data { char a; int b; };")
struct_size = ffi.sizeof("struct data") # Usually 8 (due to alignment)
# Size of existing data
data = ffi.new("char[100]")
data_size = ffi.sizeof(data) # 100Gets the natural alignment requirements for C types.
def alignof(self, cdecl):
"""
Get natural alignment size in bytes of C type.
Parameters:
- cdecl (str|CType): C type string or CType object
Returns:
int: Alignment requirement in bytes
"""Usage Examples:
# Basic type alignments
char_align = ffi.alignof("char") # 1
int_align = ffi.alignof("int") # Usually 4
double_align = ffi.alignof("double") # Usually 8
ptr_align = ffi.alignof("void *") # Usually 8 on 64-bit
# Structure alignment
ffi.cdef("struct aligned { char a; double b; };")
struct_align = ffi.alignof("struct aligned") # Usually 8Gets the byte offset of fields within structures or arrays.
def offsetof(self, cdecl, *fields_or_indexes):
"""
Get byte offset of field within structure or array element.
Parameters:
- cdecl (str): C type string for structure or array
- *fields_or_indexes: Field names or array indexes
Returns:
int: Byte offset from start of structure/array
"""Usage Examples:
# Structure field offsets
ffi.cdef("""
struct person {
char name[32];
int age;
double salary;
};
""")
name_offset = ffi.offsetof("struct person", "name") # 0
age_offset = ffi.offsetof("struct person", "age") # 32
salary_offset = ffi.offsetof("struct person", "salary") # 36 (or 40 with padding)
# Array element offsets
element_offset = ffi.offsetof("int[10]", 5) # 20 (5 * 4)
# Nested structure offsets
ffi.cdef("""
struct inner { int x, y; };
struct outer { char flag; struct inner data[3]; };
""")
nested_offset = ffi.offsetof("struct outer", "data", 1, "y")Generates C type strings from type objects with optional formatting.
def getctype(self, cdecl, replace_with=''):
"""
Get C type string representation.
Parameters:
- cdecl (str|CType): C type string or CType object
- replace_with (str): Text to insert/append (e.g., variable name)
Returns:
str: C type string representation
"""Usage Examples:
# Basic type strings
int_str = ffi.getctype("int") # "int"
ptr_str = ffi.getctype("int *") # "int *"
# With variable names
var_decl = ffi.getctype("int", "my_var") # "int my_var"
ptr_decl = ffi.getctype("int *", "my_ptr") # "int * my_ptr"
# Array declarations
array_decl = ffi.getctype("int", "[10]") # "int[10]"
# Function pointer declarations
func_decl = ffi.getctype("int(*)(int, int)", "add_func") # "int(*add_func)(int, int)"Lists all user-defined types known to the FFI instance.
def list_types(self):
"""
Get all user-defined type names.
Returns:
tuple: (typedef_names, struct_names, union_names)
"""Usage Example:
ffi.cdef("""
typedef int my_int_t;
typedef char* string_t;
struct point { int x, y; };
struct rect { struct point top_left, bottom_right; };
union value { int i; float f; char c; };
""")
typedefs, structs, unions = ffi.list_types()
print("Typedefs:", typedefs) # ['my_int_t', 'string_t']
print("Structs:", structs) # ['point', 'rect']
print("Unions:", unions) # ['value']def process_data(data):
data_type = ffi.typeof(data)
if data_type.kind == "pointer":
print(f"Pointer to {data_type.item}")
if data_type.item.cname == "int":
print("Integer pointer")
elif data_type.kind == "array":
print(f"Array of {data_type.item} with length {data_type.length}")def analyze_struct(struct_name):
struct_type = ffi.typeof(struct_name)
struct_size = ffi.sizeof(struct_type)
print(f"Structure: {struct_name}")
print(f"Total size: {struct_size} bytes")
# Analyze fields (requires accessing internal structure)
for field_name in struct_type.fields:
offset = ffi.offsetof(struct_name, field_name)
field_type = ffi.typeof(f"{struct_name}.{field_name}")
field_size = ffi.sizeof(field_type)
print(f" {field_name}: offset {offset}, size {field_size}")def calculate_padding(struct_name):
struct_size = ffi.sizeof(struct_name)
# Calculate sum of field sizes
field_total = 0
for field_name in ["field1", "field2", "field3"]: # Known fields
try:
field_size = ffi.sizeof(ffi.typeof(f"{struct_name}.{field_name}"))
field_total += field_size
except:
break
padding = struct_size - field_total
print(f"Total padding: {padding} bytes")def are_compatible(type1, type2):
"""Check if two types are assignment compatible"""
t1 = ffi.typeof(type1)
t2 = ffi.typeof(type2)
# Same type
if t1 == t2:
return True
# Pointer compatibility
if t1.kind == "pointer" and t2.kind == "pointer":
return t1.item == t2.item or t1.item.cname == "char" or t2.item.cname == "char"
# Integer type compatibility
if t1.kind == "primitive" and t2.kind == "primitive":
return t1.cname in ["int", "long", "short"] and t2.cname in ["int", "long", "short"]
return False# Check platform-specific sizes
import platform
print(f"Platform: {platform.machine()}")
print(f"Pointer size: {ffi.sizeof('void *')} bytes")
print(f"Long size: {ffi.sizeof('long')} bytes")
print(f"Size_t size: {ffi.sizeof('size_t')} bytes")
# Adjust algorithms based on sizes
if ffi.sizeof("void *") == 8:
print("64-bit platform")
else:
print("32-bit platform")def check_alignment(type_name):
size = ffi.sizeof(type_name)
alignment = ffi.alignof(type_name)
print(f"{type_name}: size={size}, alignment={alignment}")
if size % alignment != 0:
print(f"Warning: {type_name} size not aligned!")Install with Tessl CLI
npx tessl i tessl/pypi-cffi