0
# C/C++ Interoperability
1
2
Cython provides extensive capabilities for interfacing with C and C++ libraries, enabling seamless integration between Python and compiled code. This includes standard library bindings, external library interfaces, and tools for wrapping existing C/C++ codebases.
3
4
## Capabilities
5
6
### Python C API Bindings
7
8
Pre-defined declarations for the Python C API, enabling direct access to Python internals from Cython code.
9
10
```python { .api }
11
# Available cpython modules (cimport from cpython.*)
12
from cpython.object cimport PyObject, Py_INCREF, Py_DECREF
13
from cpython.list cimport PyList_New, PyList_Append, PyList_GET_ITEM
14
from cpython.dict cimport PyDict_New, PyDict_SetItem, PyDict_GetItem
15
from cpython.tuple cimport PyTuple_New, PyTuple_SET_ITEM, PyTuple_GET_ITEM
16
from cpython.string cimport PyString_AsString, PyString_FromString
17
from cpython.unicode cimport PyUnicode_AsUTF8String, PyUnicode_FromString
18
from cpython.bytes cimport PyBytes_AsString, PyBytes_FromString
19
from cpython.buffer cimport Py_buffer, PyBuffer_Release
20
from cpython.memoryview cimport PyMemoryView_FromBuffer
21
from cpython.complex cimport PyComplex_RealAsDouble, PyComplex_ImagAsDouble
22
```
23
24
### Standard C Library Bindings
25
26
Declarations for standard C library functions and constants.
27
28
```python { .api }
29
# Available libc modules (cimport from libc.*)
30
from libc.stdio cimport printf, fprintf, fopen, fclose, FILE
31
from libc.stdlib cimport malloc, free, calloc, realloc, atoi, atof
32
from libc.string cimport strlen, strcpy, strcat, strcmp, memcpy, memset
33
from libc.math cimport sin, cos, tan, sqrt, pow, log, exp, M_PI
34
from libc.time cimport time_t, clock_t, time, clock, difftime
35
from libc.errno cimport errno, ENOENT, ENOMEM, EINVAL
36
```
37
38
### C++ Standard Library Bindings
39
40
Declarations for C++ standard library containers and utilities.
41
42
```python { .api }
43
# Available libcpp modules (cimport from libcpp.*)
44
from libcpp.vector cimport vector
45
from libcpp.string cimport string
46
from libcpp.map cimport map, pair
47
from libcpp.set cimport set, unordered_set
48
from libcpp.deque cimport deque
49
from libcpp.list cimport list as cpp_list
50
from libcpp.queue cimport queue, priority_queue
51
from libcpp.stack cimport stack
52
from libcpp.algorithm cimport sort, find, binary_search
53
from libcpp.iterator cimport back_inserter
54
from libcpp.memory cimport shared_ptr, unique_ptr, make_shared
55
```
56
57
### NumPy Integration
58
59
Specialized declarations for efficient NumPy array operations and C API access.
60
61
```python { .api }
62
# NumPy integration (cimport numpy as cnp)
63
import numpy as np
64
cimport numpy as cnp
65
66
# Core array types and functions
67
cnp.ndarray, cnp.dtype, cnp.flatiter
68
cnp.int8_t, cnp.int16_t, cnp.int32_t, cnp.int64_t
69
cnp.uint8_t, cnp.uint16_t, cnp.uint32_t, cnp.uint64_t
70
cnp.float32_t, cnp.float64_t, cnp.complex64_t, cnp.complex128_t
71
72
# Memory views for efficient array access
73
cnp.int_t[:], cnp.double_t[:, :], cnp.complex_t[:, :, :]
74
```
75
76
### POSIX System Interfaces
77
78
POSIX API declarations for system-level programming.
79
80
```python { .api }
81
# Available posix modules (cimport from posix.*)
82
from posix.unistd cimport getpid, getuid, getgid, sleep, usleep
83
from posix.fcntl cimport open, O_RDONLY, O_WRONLY, O_CREAT
84
from posix.stat cimport stat, S_ISREG, S_ISDIR
85
from posix.time cimport timespec, nanosleep
86
from posix.signal cimport kill, SIGTERM, SIGKILL
87
```
88
89
### OpenMP Parallel Programming
90
91
OpenMP support for parallel computing and multi-threading.
92
93
```python { .api }
94
from cython.parallel cimport prange, parallel, threadid
95
from openmp cimport omp_get_num_threads, omp_get_thread_num, omp_set_num_threads
96
```
97
98
### External Library Declaration
99
100
Templates and patterns for declaring external C/C++ libraries.
101
102
```python { .api }
103
# External C library declaration template
104
cdef extern from "my_library.h":
105
ctypedef struct my_struct:
106
int field1
107
double field2
108
109
int my_function(int arg1, double arg2)
110
void* my_malloc(size_t size)
111
void my_free(void* ptr)
112
113
# Constants and macros
114
enum:
115
MY_CONSTANT = 42
116
117
cdef int MY_MACRO_VALUE
118
119
# External C++ library declaration template
120
cdef extern from "my_cpp_library.hpp" namespace "MyNamespace":
121
cppclass MyClass:
122
MyClass() except +
123
MyClass(int value) except +
124
int get_value()
125
void set_value(int value)
126
127
cppclass MyTemplate[T]:
128
MyTemplate() except +
129
void push_back(T& item)
130
T& operator[](size_t index)
131
```
132
133
## Usage Examples
134
135
### Python C API Direct Access
136
137
```cython
138
from cpython.object cimport PyObject, Py_INCREF, Py_DECREF
139
from cpython.list cimport PyList_New, PyList_Append
140
141
def create_optimized_list(items):
142
"""Create list using Python C API directly."""
143
cdef PyObject* py_list = PyList_New(0)
144
cdef PyObject* item
145
146
for python_item in items:
147
item = <PyObject*>python_item
148
Py_INCREF(item)
149
PyList_Append(py_list, item)
150
151
return <object>py_list
152
```
153
154
### Standard C Library Usage
155
156
```cython
157
from libc.stdlib cimport malloc, free
158
from libc.string cimport strcpy, strlen
159
from libc.stdio cimport printf
160
161
def c_string_operations(str python_string):
162
"""Demonstrate C string operations."""
163
cdef bytes byte_string = python_string.encode('utf-8')
164
cdef char* c_string = byte_string
165
cdef size_t length = strlen(c_string)
166
167
# Allocate C memory
168
cdef char* buffer = <char*>malloc(length + 1)
169
if buffer == NULL:
170
raise MemoryError("Failed to allocate memory")
171
172
try:
173
# Copy string
174
strcpy(buffer, c_string)
175
printf("C string: %s (length: %zu)\n", buffer, length)
176
177
return buffer[:length].decode('utf-8')
178
finally:
179
free(buffer)
180
```
181
182
### C++ Standard Library Integration
183
184
```cython
185
from libcpp.vector cimport vector
186
from libcpp.string cimport string
187
from libcpp.map cimport map, pair
188
from libcpp.algorithm cimport sort
189
190
def cpp_containers_demo():
191
"""Demonstrate C++ container usage."""
192
# Vector operations
193
cdef vector[int] vec
194
cdef int i
195
196
for i in range(10):
197
vec.push_back(i * i)
198
199
# Sort vector
200
sort(vec.begin(), vec.end())
201
202
# Map operations
203
cdef map[string, int] word_count
204
cdef vector[string] words = [b"hello", b"world", b"hello"]
205
206
for word in words:
207
word_count[word] += 1
208
209
# Convert to Python dict
210
result = {}
211
cdef map[string, int].iterator it = word_count.begin()
212
while it != word_count.end():
213
result[it.first.decode('utf-8')] = it.second
214
it += 1
215
216
return list(vec), result
217
```
218
219
### NumPy Array Optimization
220
221
```cython
222
import numpy as np
223
cimport numpy as cnp
224
225
def fast_array_operations(cnp.double_t[:, :] matrix):
226
"""Optimized matrix operations using NumPy C API."""
227
cdef int rows = matrix.shape[0]
228
cdef int cols = matrix.shape[1]
229
cdef int i, j
230
cdef double sum_val = 0.0
231
232
# Direct memory access without Python overhead
233
for i in range(rows):
234
for j in range(cols):
235
sum_val += matrix[i, j] * matrix[i, j]
236
237
return np.sqrt(sum_val)
238
239
def create_array_from_c_data(int size):
240
"""Create NumPy array from C data."""
241
cdef cnp.npy_intp shape[1]
242
shape[0] = <cnp.npy_intp>size
243
244
# Allocate array
245
cdef cnp.ndarray result = cnp.PyArray_EMPTY(1, shape, cnp.NPY_DOUBLE, 0)
246
cdef double[:] result_view = result
247
248
cdef int i
249
for i in range(size):
250
result_view[i] = i * 0.5
251
252
return result
253
```
254
255
### External C Library Wrapping
256
257
```cython
258
# my_library_wrapper.pyx
259
cdef extern from "external_lib.h":
260
ctypedef struct Point:
261
double x
262
double y
263
264
Point* create_point(double x, double y)
265
void destroy_point(Point* p)
266
double distance(Point* p1, Point* p2)
267
void move_point(Point* p, double dx, double dy)
268
269
cdef class PyPoint:
270
"""Python wrapper for C Point struct."""
271
cdef Point* _c_point
272
273
def __cinit__(self, double x, double y):
274
self._c_point = create_point(x, y)
275
if self._c_point == NULL:
276
raise MemoryError("Failed to create point")
277
278
def __dealloc__(self):
279
if self._c_point != NULL:
280
destroy_point(self._c_point)
281
282
property x:
283
def __get__(self):
284
return self._c_point.x
285
def __set__(self, double value):
286
self._c_point.x = value
287
288
property y:
289
def __get__(self):
290
return self._c_point.y
291
def __set__(self, double value):
292
self._c_point.y = value
293
294
def distance_to(self, PyPoint other):
295
return distance(self._c_point, other._c_point)
296
297
def move(self, double dx, double dy):
298
move_point(self._c_point, dx, dy)
299
```
300
301
### C++ Class Wrapping
302
303
```cython
304
# cpp_wrapper.pyx
305
from libcpp.string cimport string
306
from libcpp.vector cimport vector
307
308
cdef extern from "MyClass.hpp":
309
cppclass CppClass:
310
CppClass() except +
311
CppClass(string name) except +
312
313
string get_name()
314
void set_name(string name)
315
void add_value(double value)
316
vector[double] get_values()
317
double compute_average()
318
319
cdef class PyCppClass:
320
"""Python wrapper for C++ class."""
321
cdef CppClass* _cpp_obj
322
323
def __cinit__(self, str name=""):
324
cdef string cpp_name = name.encode('utf-8')
325
self._cpp_obj = new CppClass(cpp_name)
326
327
def __dealloc__(self):
328
del self._cpp_obj
329
330
@property
331
def name(self):
332
return self._cpp_obj.get_name().decode('utf-8')
333
334
@name.setter
335
def name(self, str value):
336
cdef string cpp_name = value.encode('utf-8')
337
self._cpp_obj.set_name(cpp_name)
338
339
def add_value(self, double value):
340
self._cpp_obj.add_value(value)
341
342
def get_values(self):
343
cdef vector[double] cpp_values = self._cpp_obj.get_values()
344
return [cpp_values[i] for i in range(cpp_values.size())]
345
346
def compute_average(self):
347
return self._cpp_obj.compute_average()
348
```
349
350
### OpenMP Parallel Computing
351
352
```cython
353
from cython.parallel cimport prange, parallel
354
from openmp cimport omp_get_thread_num, omp_set_num_threads
355
import numpy as np
356
cimport numpy as cnp
357
358
def parallel_sum(cnp.double_t[:] array, int num_threads=4):
359
"""Parallel array summation using OpenMP."""
360
omp_set_num_threads(num_threads)
361
362
cdef int n = array.shape[0]
363
cdef double total = 0.0
364
cdef int i
365
366
with nogil, parallel():
367
for i in prange(n, schedule='static'):
368
total += array[i]
369
370
return total
371
372
def parallel_matrix_multiply(cnp.double_t[:, :] A, cnp.double_t[:, :] B):
373
"""Parallel matrix multiplication."""
374
cdef int M = A.shape[0]
375
cdef int N = A.shape[1]
376
cdef int P = B.shape[1]
377
378
cdef cnp.double_t[:, :] C = np.zeros((M, P), dtype=np.float64)
379
380
cdef int i, j, k
381
with nogil, parallel():
382
for i in prange(M, schedule='dynamic'):
383
for j in range(P):
384
for k in range(N):
385
C[i, j] += A[i, k] * B[k, j]
386
387
return np.asarray(C)
388
```
389
390
### Advanced Memory Management
391
392
```cython
393
from cpython.mem cimport PyMem_Malloc, PyMem_Free
394
from libc.string cimport memcpy
395
396
cdef class ManagedBuffer:
397
"""Memory-managed buffer with C and Python integration."""
398
cdef void* _buffer
399
cdef size_t _size
400
cdef bint _owns_memory
401
402
def __cinit__(self, size_t size):
403
self._size = size
404
self._buffer = PyMem_Malloc(size)
405
self._owns_memory = True
406
407
if self._buffer == NULL:
408
raise MemoryError("Failed to allocate buffer")
409
410
def __dealloc__(self):
411
if self._owns_memory and self._buffer != NULL:
412
PyMem_Free(self._buffer)
413
414
def copy_from_array(self, cnp.uint8_t[:] source):
415
"""Copy data from NumPy array to C buffer."""
416
if source.shape[0] > self._size:
417
raise ValueError("Source array too large")
418
419
memcpy(self._buffer, &source[0], source.shape[0])
420
421
def as_array(self):
422
"""Return buffer contents as NumPy array."""
423
cdef cnp.npy_intp shape[1]
424
shape[0] = <cnp.npy_intp>self._size
425
426
# Create array that shares memory (no copy)
427
return cnp.PyArray_SimpleNewFromData(
428
1, shape, cnp.NPY_UINT8, self._buffer
429
)
430
```
431
432
The C/C++ interoperability features in Cython enable seamless integration with existing libraries, high-performance computing frameworks, and system-level programming interfaces, making it an ideal bridge between Python and compiled code.