0Pricing
Python Academy · Lesson

cffi: C Foreign Function Interface

Use cffi for more Pythonic C interop with inline C declarations.

cffi: C Foreign Function Interface is a free Python Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Python Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

What Is cffi?

cffi (C Foreign Function Interface) lets you call C code from Python using C declarations rather than ctypes classes. It is more Pythonic and often safer.

# pip install cffi
from cffi import FFI
ffi = FFI()

ffi.cdef("double sqrt(double x);")
libm = ffi.dlopen(None)   # current process
print(libm.sqrt(2.0))     # 1.4142...

ABI vs API Mode

ffi.dlopen() is ABI mode — calls an existing shared library at runtime. API mode compiles a C wrapper and is faster and more robust.

from cffi import FFI
ffi = FFI()

# ABI mode (no compile step):
ffi.cdef("int abs(int x);")
libc = ffi.dlopen("libc.so.6")  # Linux
print(libc.abs(-42))   # 42

cdef Declarations

Use ffi.cdef() to declare C function signatures, structs, and typedefs that you want to use from Python.

from cffi import FFI
ffi = FFI()

ffi.cdef("""
    typedef struct {
        double x;
        double y;
    } Point;

    double distance(Point a, Point b);
""")

# lib = ffi.dlopen("mylib.so")

Creating C Structs

Use ffi.new() to allocate a C struct and set its fields from Python.

from cffi import FFI
ffi = FFI()

ffi.cdef("typedef struct { int x; int y; } Vec2;")
lib = ffi.dlopen(None)

v = ffi.new("Vec2 *")
v.x = 3
v.y = 4
print(v.x, v.y)   # 3 4

Strings and Buffers

Use ffi.new("char[]", n) for mutable buffers and ffi.string(ptr) to convert a C string pointer to Python bytes.

from cffi import FFI
ffi = FFI()

buf = ffi.new("char[]", b"hello world")
print(ffi.string(buf))   # b"hello world"

# Mutable buffer for output:
out = ffi.new("char[128]")
# c_func(out, 128)  # fill the buffer
# result = ffi.string(out).decode()

API Mode with verify

API mode compiles a small C wrapper module for better type safety and performance. Use ffi.set_source() and build offline.

from cffi import FFI
ffi = FFI()

ffi.cdef("int add(int a, int b);")
ffi.set_source("_mylib",
    """
    int add(int a, int b) { return a + b; }
    """
)

# Build: python build_mylib.py
# from _mylib import ffi, lib
# print(lib.add(3, 4))   # 7

Callbacks from C to Python

Use ffi.callback() to wrap a Python function as a C function pointer that can be passed to a C library.

from cffi import FFI
ffi = FFI()
ffi.cdef("typedef int (*compare_fn)(int, int);")

@ffi.callback("int(int, int)")
def compare(a, b):
    return a - b

# pass compare to a C sort function

Memory Management

Objects allocated with ffi.new() are owned by Python and freed automatically. Use ffi.gc(ptr, destructor) to attach a custom destructor.

from cffi import FFI
ffi = FFI()

# ptr freed when Python GC collects it:
buf = ffi.new("int[10]")
buf[0] = 42
print(buf[0])   # 42

# Custom destructor:
# ptr = ffi.gc(lib.alloc(), lib.free)

cffi vs ctypes

cffi uses C declaration strings (more natural for C developers) while ctypes uses Python classes. cffi's API mode is faster; ctypes requires no compilation.

# ctypes approach:
import ctypes
libc = ctypes.CDLL("libc.so.6")
libc.abs.restype = ctypes.c_int
libc.abs.argtypes = [ctypes.c_int]
print(libc.abs(-5))   # 5

# cffi approach:
from cffi import FFI; ffi = FFI()
ffi.cdef("int abs(int);")
lib = ffi.dlopen(None)
print(lib.abs(-5))    # 5

Using cffi with NumPy

Pass NumPy array data directly to C via cffi using ffi.cast() and the array's ctypes.data pointer.

import numpy as np
from cffi import FFI
ffi = FFI()

arr = np.array([1.0, 2.0, 3.0])
ptr = ffi.cast("double *", arr.ctypes.data)
# Now ptr can be passed to a C function expecting double*

Error Handling with cffi

C functions typically signal errors via return values. Check return values and use ffi.errno for POSIX error codes.

import errno as errno_mod
from cffi import FFI
ffi = FFI()
ffi.cdef("int open(const char *path, int flags);")
lib = ffi.dlopen(None)

fd = lib.open(b"/nonexistent", 0)
if fd == -1:
    err = ffi.errno
    raise OSError(err, "open failed")

Quick Check

What method does cffi use to declare the C function signatures you want to call?

Recap

cffi uses ffi.cdef() to declare C signatures and ffi.dlopen() for ABI-mode library calls. API mode compiles a wrapper for better performance. Use ffi.new() for C memory and ffi.callback() for Python-to-C callbacks.

Frequently asked questions

Is the “cffi: C Foreign Function Interface” lesson free?

Yes — the full text of “cffi: C Foreign Function Interface” is free to read here on the web, and the Python Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Python Academy course, upgrade to CoddyKit PRO.

What will I learn in “cffi: C Foreign Function Interface”?

Use cffi for more Pythonic C interop with inline C declarations. You practise Python Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Python Academy?

No prior experience is required. Python Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “cffi: C Foreign Function Interface” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Python Academy lesson?

Yes. Every Python Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Why C Extensions? Use Cases and Trade-offs
  2. ctypes: Calling C Libraries from Python
  3. cffi: C Foreign Function Interface
  4. Writing a Python C Extension Module
← Back to Python Academy