 Open in App
Not now

# Using C codes in Python | Set 1

• Last Updated : 18 Mar, 2019

Prerequisite: How to Call a C function in Python

Let’s discuss the problem of accessing C code from Python. As it is very evident that many of Python’s built-in libraries are written in C. So, to access C is a very important part of making Python talk to existing libraries. There is an extensive C programming API that Python provides but there are many different to deal with C.

Code #1 : [`work.c`] C-Code that we are dealing.

 `#include `` ` `int` `gcd(``int` `x, ``int` `y)``{``    ``int` `g ``=` `y;``    ``while` `(x > ``0``)``    ``{``        ``g ``=` `x;``        ``x ``=` `y ``%` `x;``        ``y ``=` `g;``    ``}``    ``return` `g;``}`` ` `int` `divide(``int` `a, ``int` `b, ``int` `*` `remainder)``{``    ``int` `quot ``=` `a ``/` `b;``    ``*``remainder ``=` `a ``%` `b;``    ``return` `quot;``}`` ` `double avg(double ``*` `a, ``int` `n)``{``    ``int` `i;``    ``double total ``=` `0.0``;``    ``for` `(i ``=` `0``; i < n; i``+``+``)``    ``{``        ``total ``+``=` `a[i];``    ``}``    ``return` `total ``/` `n;``}`` ` `typedef struct Point``{``    ``double x, y;``} Point;`` ` `double distance(Point ``*` `p1, Point ``*` `p2)``{``    ``return` `hypot(p1``-``>x ``-` `p2``-``>x, p1``-``>y ``-` `p2``-``>y);``}`

Above code has different C-programming features.

gcd()
divide() – returning multiple values, one through a pointer argument
avg() – performing a data reduction across a C array
Point and distance() – involve C structures.

Let’s assume that the code above is found in a file named work.c and it has been compiled into a library libsample that can be linked to other C code. Now, we have a number of C functions that have been compiled into a shared library. So, we call the functions entirely from Python without having to write additional C code or using a third-party extension tool.

Using ctypes :
Python ctypes will come to play but make sure the C code, that is to be converted, has been compiled into a shared library that is compatible with the Python interpreter (e.g., same architecture, word size, compiler, etc.).

Further the libsample.so file has been placed in the same directory as the `work.py`. Let’s understand `work.py` now.

Code #2 : Python module that wraps around resulting library to access it

 `# work.py``import` `ctypes``import` `os`` ` `# locating the 'libsample.so' file in the``# same directory as this file``_file ``=` `'libsample.so'``_path ``=` `os.path.join(``*``(os.path.split(__file__)[:``-``1``] ``+` `(_file, )))``_mod ``=` `ctypes.cdll.LoadLibrary(_path)`

Code #3 : Accessing code

 `# int gcd(int, int)``gcd ``=` `_mod.gcd``gcd.argtypes ``=` `(ctypes.c_int, ctypes.c_int)``gcd.restype ``=` `ctypes.c_int`` ` `# int divide(int, int, int *)``_divide ``=` `_mod.divide``_divide.argtypes ``=` `(ctypes.c_int, ctypes.c_int,``                    ``ctypes.POINTER(ctypes.c_int))`` ` `_divide.restype ``=` `ctypes.c_int`` ` `def` `divide(x, y):``    ``rem ``=` `ctypes.c_int()``    ``quot ``=` `_divide(x, y, rem)``    ``return` `quot, rem.value`` ` `# void avg(double *, int n)``# Define a special type for the 'double *' argument``class` `DoubleArrayType:``    ``def` `from_param(``self``, param):``         ` `        ``typename ``=` `type``(param).__name__``         ` `        ``if` `hasattr``(``self``, ``'from_'` `+` `typename):``            ``return` `getattr``(``self``, ``'from_'` `+` `typename)(param)``         ` `        ``elif` `isinstance``(param, ctypes.Array):``            ``return` `param``         ` `        ``else``:``            ``raise` `TypeError(``"Can't convert % s"` `%` `typename)`` ` `    ``# Cast from array.array objects``    ``def` `from_array(``self``, param):``        ``if` `param.typecode !``=` `'d'``:``            ``raise` `TypeError(``'must be an array of doubles'``)``         ` `        ``ptr, _ ``=` `param.buffer_info()``        ``return` `ctypes.cast(ptr, ctypes.POINTER(ctypes.c_double))``         ` `    ``# Cast from lists / tuples``    ``def` `from_list(``self``, param):``        ``val ``=` `((ctypes.c_double)``*``len``(param))(``*``param)``        ``return` `val``     ` `    ``from_tuple ``=` `from_list``     ` `    ``# Cast from a numpy array``    ``def` `from_ndarray(``self``, param):``        ``return` `param.ctypes.data_as(ctypes.POINTER(ctypes.c_double))`` ` `DoubleArray ``=` `DoubleArrayType()``_avg ``=` `_mod.avg``_avg.argtypes ``=` `(DoubleArray, ctypes.c_int)``_avg.restype ``=` `ctypes.c_double`` ` `def` `avg(values):``    ``return` `_avg(values, ``len``(values))`` ` `# struct Point { }``class` `Point(ctypes.Structure):``    ``_fields_ ``=` `[(``'x'``, ctypes.c_double), (``'y'``, ctypes.c_double)]``     ` `# double distance(Point *, Point *)``distance ``=` `_mod.distance``distance.argtypes ``=` `(ctypes.POINTER(Point), ctypes.POINTER(Point))``distance.restype ``=` `ctypes.c_double`

Now, one can easily load the module and use the resulting C functions. See the next part – Using C codes in Python | Set 2.

My Personal Notes arrow_drop_up