# Python/C API - sum/add 2 integers

Hi, this topic is about how you can call simple Python/C functions to sum 2 integers.

Let’s dive in:

shako@shako-localhost:~/REPOS/cpython/debug$ gdb ./python
(gdb) break main 
Breakpoint 1 at 0x591aa: file ../Programs/python.c, line 14.
(gdb) run Starting program: /home/shako/REPOS/cpython/debug/python 
[Thread debugging using libthread_db enabled] 
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main (argc=1, argv=0x7fffffffdec8) at ../Programs/python.c:14 
14 {

We put break at main function to stop python at very “beginning”. Then we can call functions. First let’s create new int object:

(gdb) call PyLong_FromLong(11111)
$1 = (PyObject *) 0x7ffff7f8e040

What we did here is basically calling C function PyLong_FromLong(longobject.c#L243 (opens new window))

As commented in source code this will create a new int object from C long int type.

There is a call for _PyLong_New(longobject.c#L195 (opens new window)) which is allocating memory for given int:

/* Allocate a new int object with size digits.
 Return NULL and set exception if we run out of memory. */

And if you notice those function return type is PyObject as most of things in Python. Next run is for creating new integer object:

(gdb) call PyLong_FromLong(22222)
$2 = (PyObject *) 0x7ffff7f8e090

If you are curious about what is this int object:

(gdb) p *$2
$3 = {_ob_next = 0x7ffff7f8e040, _ob_prev = 0x555555a58660 <refchain>;, ob_refcnt = 1, ob_type = 0x555555a54ee0 <PyLong_Type>}
(gdb) p *$2->ob_type
$4 = {ob_base = {ob_base = {_ob_next = 0x0, _ob_prev = 0x0, ob_refcnt = 1, ob_type = 0x555555a5f720 <PyType_Type>}, ob_size = 0}, tp_name = 0x5555557c433f "int",
...(Truncated output)...

So the integer object type is PyLong_Type which is type of PyType_Type 😃 Next we need to add these numbers(objects in our term).

Prior to this let’s see the type definition for PyLong_Type(longobject.c#L5379 (opens new window)) ; if you follow link you will see:

long_as_number, /* tp_as_number */

Same thing you can see from debugger as well:

(gdb) p PyLong_Type
$10 = {ob_base = {ob_base = {_ob_next = 0x0, _ob_prev = 0x0, ob_refcnt = 1, ob_type = 0x555555a5f720 <PyType_Type>}, ob_size = 0}, tp_name = 0x5555557c433f "int",
  tp_basicsize = 40, tp_itemsize = 4, tp_dealloc = 0x5555555d9788 <long_dealloc>, tp_print = 0x0, tp_getattr = 0x0, tp_setattr = 0x0, tp_as_async = 0x0,
  tp_repr = 0x5555555dc451 <long_to_decimal_string>, tp_as_number = 0x555555a54b20 <long_as_number>;
...(Truncated Output)...

Then let’s see what we have in tp_as_number:

(gdb) p *PyLong_Type->tp_as_number
$12 = {nb_add = 0x5555555de646 <long_add>, nb_subtract = 0x5555555de75e <long_sub>, nb_multiply = 0x5555555e19a9 <long_mul>, nb_remainder = 0x5555555e00b6 <long_mod>,
...(Truncated Output)...

Can be explored from link longobject.c#L5342 (opens new window) So now we see nb_add which is a long_add binary function which is stored at longobject.c#L3083 (opens new window)

(gdb) p PyLong_Type->tp_as_number->nb_add 
$14 = (binaryfunc) 0x5555555de646 <long_add>; 
(gdb) p *PyLong_Type->tp_as_number->nb_add 
$15 = {PyObject *(PyObject *, PyObject *)} 0x5555555de646 <long_add>;

Now it is clear how we are going to add 2 integers:

(gdb) call PyLong_Type->tp_as_number->nb_add(0x7ffff7f8e040, 0x7ffff7f8e090) 
$16 = (PyObject *) 0x7ffff7f8e0e0

How about printing this final result?:

(gdb) call PyObject_Print(0x7ffff7f8e0e0, stderr, 1)

Program received signal SIGSEGV, Segmentation fault. 
0x00005555555f8f8b in PyObject_Str (v=v@entry=0x7ffff7f8e0e0) at ../Objects/object.c:524 524 if (Py_EnterRecursiveCall(" while getting the str of an object"))

After some research I found that this is happening because, we did not called Initialization Py_Initialize() (opens new window)

For more read here - Initialization, Finalization, and Threads pre-init-safe (opens new window)

(gdb) call Py_Initialize() [some errors may occur here]

(gdb) call PyObject_Print(0x7ffff7f8e0e0, stderr, 1) 
33333$19 = 0

That’s it. Now you should have very basic grasp of what is going on in Python/C API.