Here, in this tutorial, I am going to tutor you a simple Python wrapper for C library. And how to call C functions from Python?
Before beginning this, let’s see…
Till now I have talked about many plus points about Python.
But…
There is One of the major disadvantages of Python – its execution speed. 🙁 Python is slower than many of the competitive programming language like C, Java…
C and CPP is a very standard programming language. And there are so many libraries already available in C.
To enhance the speed of the Python and to make the reuse of existing C libraries, the concept of calling C functions from Python is useful.
So there are two advantages of using C libraries (or C functions):
In fact, there are many Python inbuilt standard libraries are written in C. You may not have noticed it, but many times when you call inbuilt function, it executes C function internally.
So coming to our coding part…
How to create these C libraries?
In this tutorial, I am going to tell you, how to compile a C program to create a library and step by step procedure for calling C functions from Python code.
Steps…
To understand this tutorial, we will create an arithmetic application where all the arithmetic definition are written in C. And we will write a wrapper using Python called calci
that will call the function written in C program.
Let’s begin…
First of all, write a simple C program with functions definition.
Even if you know the basics of C and C++ programming, you can write the function in C that performs the basic arithmetic operations.
Following is code in C.
#include <stdio.h> #include <stdlib.h> #include "arithmatic.h" void connect() { printf("Connected to C extension...\n"); } //return random value in range of 0-50 int randNum() { int nRand = rand() % 50; return nRand; } //add two number and return value int addNum(int a, int b) { int nAdd = a + b; return nAdd; }
Note: There is no function main()
in the above program. There are only function definitions that we are going to call them from the Python program.
Save the above program as arithmatic.c
.
We may have noticed in above C program as we have included header file as arithmatic.h
.
void connect(); int randNum(); int addNum(int a, int b);
This header file contains declarations of all the arithmetic functions.
Save the file as aithmatic.h. in the same directory.
You need gcc compiler to compile C program.
To use that C function in Python you need to compile and generate the shared object.
Now Compile C program Using gcc Compiler:
gcc -c -fPIC arithmatic.c -o arithmatic.o
It will generate .o
file. Run below command to get the shared object .so
file from .o
.
gcc arithmatic.o -shared -o libcalci.so
It will create the file libcalci.so
.
Another way using the Single Command:
We are only interested in file .so
(shared object). So, we can skip creating .o
file.
You can merge above two commands into one, that will give you shared object without getting .o
object file.
gcc -shared -o libcalci.so -fPIC arithmatic.c
After running this command you see the file libcalci.so is generated in the current directory.
Backend C library (libcalci.so
) is ready to use. We can import it into our Python program to use it.
Note: You need to generate shared object .so
file for Linux, OS X, etc. For the Window OS, you need to generate .dll
file.
As like Python programming, writing wrapper is easier than it sounds.
To call C functions from Python wrapper, you need to import ctypes
foreign function library in Python code.
(You can read more about this library on Python official document.)
Load .so file that we have created in the previous step by creating an instance of CDLL. Just call to its constructor function CDLL(). It returns the object variable (says libCalc).
Now, with this object variable, you can call and pass input parameters to C functions just like calling normal Python class functions.
Here is a simple code.
from ctypes import * libCalc = CDLL("./libcalci.so") #call C function to check connection libCalc.connect() #calling randNum() C function #it returns random number varRand = libCalc.randNum() print "Random Number:", varRand, type(varRand) #calling addNum() C function #it returns addition of two numbers varAdd = libCalc.addNum(20,30) print "Addition : ", varAdd
Output:
Connected to C extension... Random Number: 27 <type 'int'> Addition: 50
In the program, we used function type() to identify the return data type of the C function’s variable.
This is all about creating C library and calling C functions with Python. If you have any question or doubt, write in a comment. I do reply to all comments.
Some points to Acknowledge:
Before learning Python, I learned C programming. Whenever I require, many times I reuse existing C programs (those are written earlier on my system) in Python. It saves me lots of time. Even, it is the useful approach of writing your own C library and executing complex logic faster in C functions.
Hope you enjoy this tutorial.
If you want to be the expert Python programmer, you can follow my complete Python tutorial for FREE.
Happy Programming!
How to access global variable of c in python ?
Hi Akshay,
I did not try it. Will try it and will let you know.
Hey Aniruddha,
Have you ever tried writing a python wrapper to create a C file and add instructions into the C file using python scripting? and later compile it in the end?
Hi Ewig,
I did not come across any such necessity. But, I think it’s doable.
This is definitely doable and as simple as writing to files like any other in Python just with a .c extension and then using a shell call to compile said files.
Can I call C program from python that uses wiringPi to write to an LCD 20×2 through an MCP23017 chip? I am using the LCD 20×2 to display the date and time and CPU temperature of a raspberry pi.
Thank you
Hi Perry.
I am not much into raspberry pi and other hardware chips, and did not come across this situation. So not sure right now.
Thanks!
Many have done similar projects for Micropython, a python distribution for microcontrollers. Just google for it. surprisingly, these projects have made use of Python for raspberry pi and Arduino projects source code.
This article really helped me understand C. Thanks, Aniruddha Chaudhari.
Thanks, Hadi for sharing your thought. I hope, Perry will find it helpful.
Hi,
Is it possible to call Scala code from python without pyspark like above code (calling c code from python)? Is it possible to call Scala code from python like above?
Hi Jinnu,
I am not sure about it as I have never tried that.
Hey, how can I use a C function to create a new column in a pandas data frame using “apply”?
C functions are used to implement some algorithms and logic. It is difficult to retain the Python data types in C.
In your case, you can write C function that manipulates and creates the desired array. Return this array data to the Python and then append that array to Pandas data frame as a new column in Python.
How can I do it in the opposite way? like How can I call python functions from C programming?
You can call Python function from C. It is not so straightforward though. You can refer to this document.
Your page /calling-c-functions-from-python was the only internet source that worked right for me.
BTW change gcc hello.o to gcc arithmetic.o, otherwise it fails.
Hi Brian, I am glad as this page has helped you to solve your problem.
Thanks for the correction. Edited!
Hello!
I have a problem with the C function parameters.
When I set a string parameter in a C function through python, it reads only the first character of the string. I’m wondering if it’s a type error because the string type in python is different from C.
how can I fix this? Is there a way to pass a string that is compatible with C?
note: this problem occurs only when I use python3.7, if I use python2.7 interpreter, it works fine.
note2: sorry about my English. I’m Brazilian xD
Hi Cassio,
As your code is working with Python2.7 and not working with Python 3.7, there is a change in string implementation in both the versions.
By default string in Python 2 is ASCII type whereas string in Python 3 is Unicode. Try typecasting the string in your code.
Please let me know if this works for you.
How to access the char array returned from C program, as of now the program is returning the memory address of the pointer.
Maniganda, if you know the address of pointer you can access the pointer and then character string. Not sure about the problem you are facing.
Is it possible to call c functions of Linux c executable (not .so file) from python?
You can not do it directly. You can execute a compiled C program (.exe file) from the Python program using a subprocess module by running the executable file using subprocess.open() method in Linux.
Hi,
How can I do so if I have string arguments and double Array arguments?
Hi Shaleen.
This will be tricky. Whenever we return a string or double array, the function does not return actual value, but it returns a pointer to these data objects.
You have to explicitly save these arguments in the dynamic memory and then return the reference from C to Python.
Hi,
Actually I am using dalsa teledyne camera which has a default .so called libGevapi.so file. I am trying to access the functions of that library from python using ctypes method as shown by you. The functions can be accessed but it is not returning correct results.
Jst, for example, there is a function called GevDevicecount which returns no. of devices connected to the system. When I am directly running the C code to access the function it returns 2 devices connected. But when I access the same function from python using ctypes method it returns 0. where 2 is the correct result.
can you help me where the issue is?
Hi Pooja. Looks like there is a mismatch of the return data type. Try with different expected return values (says 3, 4), if it is still returning 0, most probably a problem is with the expected data type of the return variable.
Hey, very helpful tutorial, thanks so much! My question is, how do I use Python to run a C function that normally needs to be run with sudo?
If the user running the Python program has root privilege, you can run the C function (even it needs to be run with Sudo). Another way, you can grant the executable permission to the C program for the normal user.
This step by step tutorial is a neat solution to exactly the problem I was facing. Very concise and clear. Thank you! Kind regards, Mathias from Germany.
Wow. You’re welcome, Mathias! I hope you will enjoy going through my other tutorials also. And Kindly share your feedback about other tutorials if you go through any. Stay safe!
Excellent tutorial, congratulation! I am just looking for a (and can’t find any) suitable makefile, in which I would just list all .o files (created from their c source files) and finally would get their .so files using the same names as the original C source files. Do you have some ideas? Thanks in advance for your reply.
Regards,
Peter
Thanks Peter for your kind words!
Can you check the make file tutorial? And please let me know if you still have a problem.
Thanks for a prompt reply. Well, I have to admit that I am a little bit “rusty” with the makefiles as I haven’t used them for the last 15 years (a side efect of using MS Visual Studio 🙂 ), but yes, there is no problem to write and execute something like:
But imagine, I want to have several other pairs of Funx.c and Funx.h in the same folder and to create the shared library files of all of them. If I write the makefile like:
only the first command line (for LibFun1) will be executed. So, is there a way to create a makefile such a way that all shared library files will be created with just one “make” call?
And I have a second question regarding a shared library function, which would return more than just a single value. For example, in your tutorial the Connect() function will print the text into the C “console”, but I want to see it in the Python “window”. So, how can the Connect() function return an entire string to the Python variable?
Thanks in advance for your reply!
Regards,
Peter
Hi Aniruddha,
I made further experiments (well, on the Raspberry Pi, where I am doing all these experiments), and I found out that to return a string (or any aggregated variable) from a C function to Python program, you can do so only via a reference type function argument. Return won’t work! For example, the code which normally work in a C program:
will not work with the Python. Instead of the string, the RetStr() function will return a number, apparently the st address. The only way (well, based on my limited observations) how to return a string is as follows:
and in the Python program to call this C function as:
And the txt has to be long enough to receive the entire text string from C. If txt is defined like
txt = ""
, nothing will be copied. This surprises me, as I expected that theRetStr()
function would create another txt object with the length and content depending only on whatRetStr()
provides.Regards,
Peter
Thanks, Peter for sharing your experience. This also surprises me a bit. It’s been a while I worked on this. I have to look into it. I will share if I get any different thoughts.
Hi Aniruddha,
As sitting at home due to both, pandemic and bad weather (imagine, we’ve got snow again in Ottawa, Canada) I have a lot of time to play with the Raspberry Pi, so I found out how to properly retrieve a string value returned by a C function as a pointer to char.
Here is the C library function:
And here is the Python code:
Regards,
Peter
Hi Peter,
Yeah, time is not really good.I’m really impressed the way you are utilizing this time at the best.
At last, you featured it out the passing string. Awesome!
Stay Home and Stay Safe, Peter!
And keep sharing your findings with us.
Regards,
Ani
You are a star, sir! A helpful tutorial.
Thanks, Jeff! It’s always a pleasure to see if the readers finding tutorial helpful for them.
I cannot get my C code to return a string. Is there a secret to it?
Is there something special to be done on the python 3 side?
Not sure what exactly is the problem. Just to give you heads up, in Python 2, string type is ASCII. And in Python 3, string type is Unicode. Check if you have a mismatch with the string formating.
suppose I have a c code that compiles using external libraries (along with paths), in the following way:
then in your step 3, should I be adding these extra arguments when making the shared object (as below)?
I’m really not sure about those extra attributes you mentioned. Still, I would recommend trying with and without these attributes. Whichever works, it would be the way to go.