When calling a c function using ctypes.CDLL in Python, the function always gets 0 passed along as argument

The c function I am trying to call:

#include <stdio.h>    
#include <stdlib.h>    
  
int main(int argc, char *argv[]){       
    long long int n = atoll(argv[1]);    
    printf("main(%lld)n", n);    
    int m = 0;         
    while (n > 1) {           
        m++;                  
        if (n % 2 == 0) {   // even    
            printf("%lld = %lld/2 n", n/2, n);    
            n = n/2;    
        }    
        else {    
            printf("%lld = 3*%lld+1 n", 3*n+1, n);    
            n = 3*n + 1;    
        }    
    }        
    printf("Collatz(%lld) is '%d'n", n,m);    
    return m;    
}    

My python code that attempts to call it with parameter 4

from ctypes import *    
import os, sys                                                                    
                                                                                    
print("you typed:", sys.argv[1])                                                  
                                                                                    
filename = sys.argv[1].split(".")[0]                                              
                                                                                    
os.system(f"gcc -c -fPIC {filename}.c -o {filename}.o && gcc {filename}.o "      
           f"-shared -o {filename}.so")                                           
       
soFile = CDLL(os.getcwd() + "/" + filename + ".so")    
       

soFile.main(4)       # <----------

In vim I run the following:

:!python test.py "collatz-loop"                                                
you typed: collatz-loop
main(0)
Collatz(0) is '0'

Notice how the output is 0. Even if I change the parameter to something other than 4, the output is always 0.

If I try to change soFile.main(4) to something with, say, two parameters, like soFile.main(2, 4), I get

:!python test.py "collatz-loop"

shell returned 139

Why is this happening, and how do I fix it?

  • I am new to c by the way, though very familiar with Java. They seem very alike syntactically.
  • Yes, I did remember to save/write the python and c file before running the .py file.

Answer

TLDR for comment thread: You should split it into 2 funcs, main and collatz (int collatz(long long n)) and make main just pass atoll(argv[1]) to collatz, so you can run it normally as an executable and also from your python script file as a shared library. You also need to set the argtype in ctypes to long long(I think it defaults to int).

C:

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

int collatz(long long n){
    int m = 0;
    while (n > 1) {
        m++;
        if (n % 2 == 0) {   // even
            printf("%lld = %lld/2 n", n/2, n);
            n = n/2;
        }
        else {
            printf("%lld = 3*%lld+1 n", 3*n+1, n);
            n = 3*n + 1;
        }
    }
    printf("Collatz(%lld) is '%d'n", n,m);
    return m;
}

int main(int argc, char *argv[]){
    long long int n = atoll(argv[1]);
    printf("main(%lld)n", n);
    collatz(n);
}

Python:

from ctypes import *
import os, sys

print("you typed:", sys.argv[1])

filename = sys.argv[1].split(".")[0]

os.system(f"gcc -c -fPIC {filename}.c -o {filename}.o && gcc {filename}.o " 
           f"-shared -o {filename}.so")

soFile = CDLL(os.getcwd() + "/" + filename + ".so")


soFile.collatz.argtypes = [c_longlong]
soFile.collatz(4)

Note: Not directly related to this issue, but you should check to make sure argc > 2 in your C code to avoid an out of bounds read if no args are passed.

Leave a Reply

Your email address will not be published. Required fields are marked *