Skip to content

Instantly share code, notes, and snippets.

@lebedov
Last active October 3, 2016 21:03
Show Gist options
  • Save lebedov/a5cf4a2233ad44b7d2cd to your computer and use it in GitHub Desktop.
Save lebedov/a5cf4a2233ad44b7d2cd to your computer and use it in GitHub Desktop.
How to expose the raw bytes in Python container classes to C functions using Cython.

Accessing Raw Bytes in Container Classs Using Cython

Description

This gist demonstrates how to expose the raw bytes encapsulated by several Python container classes to a C function using Cython.

Usage

  1. Make sure you have Cython installed.
  2. Build the included extension by running make.
  3. Run the demo file test.py.

License

This software is licensed under the BSD License by Lev Givon.

# How to expose a C function to various Python container classes.
cdef extern from "myfuncs.h":
unsigned char _sum "sum"(unsigned char *, int)
from cpython.buffer cimport PyBUF_SIMPLE
from cpython.buffer cimport Py_buffer
from cpython.buffer cimport PyObject_GetBuffer
def sum(s):
cdef Py_buffer buf
PyObject_GetBuffer(s, &buf, PyBUF_SIMPLE)
return _sum(<unsigned char *>buf.buf, buf.len)
funcs:
python setup.py build_ext --inplace
test: funcs
gcc -L. test.c -o test -lmyfuncs
clean:
rm -f test *.o *.so funcs.c
/* Simple shared library. */
#include "myfuncs.h"
unsigned char sum(unsigned char *x, int n) {
unsigned char result = 0;
int i;
for (i=0; i < n; i++) {
result += x[i];
}
return result;
}
unsigned char sum(unsigned char *x, int n);
#!/usr/bin/env python
from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize
extensions = [
Extension('libmyfuncs',
sources=['myfuncs.c'],
headers=['myfuncs.h']),
Extension('funcs',
sources=['funcs.pyx'],
libraries=['myfuncs'],
library_dirs=['.'])
]
setup(ext_modules = cythonize(extensions))
/* Test of function provided by myfuncs library. */
#include <stdio.h>
#include "myfuncs.h"
int main(void) {
unsigned char x[] = {1, 2, 3};
unsigned char result;
result = sum(x, 3);
printf("%i\n", result);
}
#!/usr/bin/env python
# Test the extension:
import funcs
import numpy as np
a = np.array([1, 2, 3], dtype=np.uint8)
s = '\x01\x02\x03'
b = bytearray([1, 2, 3])
print funcs.sum(a)
print funcs.sum(s)
print funcs.sum(b)
a = np.array([1, 2, 3], dtype=np.uint32)
s = a.tostring()
b = bytearray(a)
print funcs.sum(a)
print funcs.sum(s)
print funcs.sum(b)
a = np.array([1, 2, 3], dtype=np.float64)
s = a.tostring()
b = bytearray(a)
print funcs.sum(a)
print funcs.sum(s)
print funcs.sum(b)
@wbolster
Copy link

wbolster commented Oct 3, 2016

don't forget to PyBuffer_Release(&buf)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment