For Developers

Ctypes Modules and their Implementation in Python

ctypes modules & its implementation in Python.

Ctypes modules are foreign function libraries that provide C-compatible data types and allow the calling functions in shared libraries or dynamic link libraries. In a foreign function library, the Python code will call C functions using only Python, without any special or custom-made extensions.

Ctypes modules are the most powerful library available for Python developers. They enable you to call functions in dynamically interlinked libraries and use them for low-level memory manipulations.

This article will explore how to use this Python library for real-world cases.

Importing with Ctypes

Start by importing a basic library with a single function over to Python programming with the help of Ctypes. Note that you cannot link your regular .c file to this. You can generate a shared library with the following code:

gcc -fPIC -shared -o clibrary.so clibrary.c

clibrary will be the name of the C file. You can choose the name according to your data so that it will be easier to get it back when required.

Create your first code with the .c file:

#include <stdio.h>

void prompt ()
{
printf (“Good Day!/n”);
}

Next, go to the Python file, import the ctypes, and use the CDLL function to load up the shared library file. Make sure to include the full path to the shared library if it's not in the same directory.

import ctypes

libObject = ctypes.cdll(‘clibrary.so’)

The CDLL function will return a library object that can be used to access the functions within the library.

Calling C functions

Once you are ready with the library object, call the function from the library as a method of the library object.

libObject = ctypes.cdll(‘clibrary.so’)

libObject.prompt()

Good Day!

The above code will execute the function successfully. Now, try calling the function by passing an integer into it. Make sure to generate a new .so file after the changes for future reference.

import ctypes

testlib = ctypes.cdll(‘clibrary.so’)
testlib.prompt(18)

The number 18 was entered

Using function signatures for calling functions

There are alternatives for using the call functions other than the technique mentioned above. Let's try creating a function in C Creative that will add two numbers and provide the result.

int add(int 2, int 5)

{
return 2+5;
}

When you want to execute the same for the Python file, you will need to acquire the function signature with:

addTwoNumbers = clibrary.add

You can also keep the same name when you want to. Note that add = clibrary.add is valid. Now, you need the function for the return type which requires the code:

addTwoNumbers,argtypes = [ctypes.c_int, ctypes.c_int]

addTwoNumbers.restype = ctypes.c_int

The argtypes is for representing the parameters and the restype is for the type of return value you need. Argtypes take multiple values and restype takes a single value.

Strings

When dealing with strings in Python or C, there will be problems as strings are immutable. They can only be overwritten altogether in C and C++ strings.
Below is a simple C function that will print out the message passed through it:

import ctypes

clibrary = ctypes.cdll(‘clibrary.so’)
clibrary.display(b”Good World”)
Good World

The code will print the string mentioned in the C function. The b before the message is for declaring a binary output which is important for C compatibility.

Supported or unsupported data types

You can now modify the string within the C function. The C function will increment each item in the string by one. When there is a character A, it will become B according to the alphabet codes.
Let’s pass the string from Python into this function:

import ctypes

clibrary = ctypes.cdll(‘clibrary.so’)
string = “Good Day”
print (“Good Morning:”, string)

clibrary.increment(string)
print (“Good Evening”, cstring)
Good Morning: Good Day
Good Evening: Good Day

Python strings are not compatible with C, so there is no change in the output. You can solve this by using some ctypes data types that are compatible with C. Instead of a Python string, use a character pointer from ctypes. Each ctypes data type has an attribute that returns a native Python object that will help you return a string from the char pointer.

Creating mutable memory with string buffers

When using char pointers, you are not dealing with mutable memory but an immutable one. Assigning a new value to it will see a new memory location assigned to the string with that value. This might cause a problem with functions that expect to receive mutable memory.

Here’s an example that explains the same:

import ctypes

clibrary = ctypes.cdll(‘clibrary.so’)
cstring = ctypes.c_char_p(b”Hello World!”)
print (“Good Morning:”, cstring, cstring.value)

cstring.value = b”Good Day”
print (“Good Evening”, cstring, cstring.value)
Good Morning: c_char_p(XXXXXXXXXXXXX) b’Hello World!’
Good Evening: c_char_p(XXXXXXXXXXXXX) b’Good Day’

You can see from the output above that the address varies after each assignment. To resolve this, create string buffers using ctypes. Include the code lines “cstring = ctypes.create_string_buffer” in place of “cstring = ctypes.c_char_p” and clibrary.increment(cstring) in line five.

The string will now be properly modified. Creating a string buffer with ctypes will give mutable memories that can be used with C functions. You can also choose to pass an integer instead of a string to create an empty string buffer of that size.

Managing memory using pointers

Managing memory using pointers in ctypes is another important aspect to work on. Both C and C++ use pointers, but pointers themselves aren’t available as a data type in Python. The ctypes library will give ctypes.POINTER that can be used to create a pointer in Python.

Here are some examples of ctypes pointer:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char* alloc_memory(void)
{
char* str = strdup (“Hello World!”);
printf(“Your memory is allocated…\n”);
return str;
}
void free_memory (char* ptr)
{
printf(“Free up the space..\n”);
free (ptr);
}

First, declare two functions to your library, one for memory allocation and the other for freeing up the memory. Functions alloc_memory() and free_memory() are created for the purpose.

Allocate the required memory with the help of the allocating memory function, and free it up with the free memory when needed.

import ctypes

clibrary = ctypes.cdll(‘clibrary.so’)
alloc_func = clibrary.alloc_memory
alloc_func.restype = ctypes.POINTER(ctypes.c_char)

free_func = clibrary.free_memory
free_func.argtypes = [ctypes.POINTER(ctypes.c_char)]

cstring_pointer = alloc_func()
str = ctypes.c_char_p.from_buffer(cstring_pointer)
print (str.value)

free_func (cstring_pointer)

Creating a pointer

It’s slower to create a pointer than directly using ctypes.POINTER. It takes the parameter as the pointer type that you wish to create - whether it’s an integer or a character. On the other hand, when you use ctypes.pointer(), it takes the parameter as an object that returns the value of the pointer. Keep in mind that pointer() will accept data types from the ctypes module, so you cannot make it work on Python.

You can use the contents attribute to access the object for which the pointer is pointed. You can get further access to the value of the attribute to print out its actual Python value than a ctype object.

Using C++

C++ can be used with Python by using ctypes. However, it is trickier and there may be limitations. The shared library works in the same manner but with .cpp instead of .c as an extension.

C++ supports Function Overloading which mangles the function names. In order to create unique function names, the system will constantly check and change them.

The name change is performed on each function, regardless of their functions. When you try to call a C++ function from a shared library in Python using ctypes, it will return an error message stating that the function is not found. Fortunately, this is easily fixable: wrap it inside an external C function that will disable name mangling and allow the code to run using ctypes.

#include <iostream>

extern “C”
{
void display()
{
std:: cout << “Good Day!\n”;
}
}

import ctypes

clibrary = ctypes.CDLL(‘cppLibrary.so)
clibrary.display()
Good Day!

Now that you understand ctypes modules and how to implement them in Python, you can use them for real-world cases. The codes given above are only for reference; feel free to modify them with any function you require, depending on your needs.

Press

Press

What's up with Turing? Get the latest news about us here.
Blog

Blog

Know more about remote work. Check out our blog here.
Contact

Contact

Have any questions? We'd love to hear from you.

Hire and manage remote developers

Tell us the skills you need and we'll find the best developer for you in days, not weeks.

Hire Developers