_ctypes.c — ctypes C implementation
Modules/_ctypes/_ctypes.c is the core C extension backing the ctypes module. It defines the
CData base type, all metaclasses (SimpleType, StructType, UnionType, PointerType),
the StgDict storage-descriptor dict, and the foreign-function call machinery.
Map
| Lines | Symbol | Role |
|---|---|---|
| 1–120 | includes, CDataObject struct | Base object layout: b_ptr, b_length, b_objects |
| 121–400 | StgDict_new / StgDict_clone | Per-type storage descriptor dict |
| 401–900 | SimpleType_new | Metaclass that maps format chars to C types |
| 901–1400 | StructType_new / UnionType_new | Struct/union layout via _ctypes_alloc_format_string |
| 1401–2200 | PyCFuncPtr / CDLL wrappers | Foreign function pointer boxing |
| 2201–3000 | _build_result | Decode return value after foreign call |
| 3001–3800 | argtypes / restype setters | Argument marshalling descriptors |
| 3801–5500 | getsets, type objects, module init | PyModuleDef, type registrations |
Reading
CData base layout
Every ctypes value inherits from CDataObject. The two key fields are b_ptr (raw memory pointer)
and b_length (byte count of the owned buffer).
// CPython: Modules/_ctypes/_ctypes.c:87 CDataObject
typedef struct {
PyObject_HEAD
char *b_ptr; /* pointer to memory block */
int b_needsfree; /* must we free the memory? */
CDataObject *b_base; /* pointer to base object or NULL */
Py_ssize_t b_size; /* size of memory block in bytes */
Py_ssize_t b_length; /* number of fields */
PyObject *b_objects; /* references we need to keep */
union value b_value;
} CDataObject;
b_objects is a dict that pins Python objects whose memory is referenced by b_ptr, preventing
premature garbage collection during a foreign call.
SimpleType metaclass
SimpleType_new is called when user code writes class MyInt(ctypes.c_int): pass. It reads the
_type_ class attribute (a single format character such as "i") and wires up the correct
getfunc/setfunc pair from the internal fielddesc_table.
// CPython: Modules/_ctypes/_ctypes.c:432 SimpleType_new
static PyObject *
SimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *result;
PyObject *proto;
const char *proto_str;
Py_ssize_t proto_len;
StgDictObject *stgdict;
struct fielddesc *fmt;
result = PyType_Type.tp_new(type, args, kwds);
if (!result)
return NULL;
proto = PyObject_GetAttrString(result, "_type_");
/* ... fielddesc_table lookup, stgdict population ... */
return result;
}
The fielddesc_table maps each format character to a (getfunc, setfunc, size, align) tuple so
that SimpleType never needs to hardcode individual C types.