pythonctypescdecl

How can ctypes infer the types of integers that are passed?


I am interfacing this C code:

extern "C" void print_int(short a, int b, long c, long long d)
{
   printf("%hi %i %li %lli", a, b, c, d);
}

with this Python code:

from ctypes import *
lib=cdll.LoadLibrary("./libtest.so")
lib.print_int(1,2,3,4)

Even if I don't cast the arguments in print_int code, they are passed correctly and I get:

1 2 3 4

as expected. Why cannot ctypes do the same form floating-point numbers? The following snippet:

extern "C" void print_float(float a, double b, long double c)
{
   printf("%f %lf %Lf", a, b, c);
}

would require an explicit cast from ctypes otherwise an exception is raised.

lib.print_float(c_float(1.0), c_double(2.0), c_longdouble(3.0))

I am working in Unix, compiling with the cdecl calling convention if that matters.


Solution

  • Because defaults and stack size. If you don't specify the type, ctypes assumes c_int. On a 64-bit system the stack is 64-bit, so shorts, ints, longs, long longs all are sign-extended and use a 64-bit stack slot. long long would break on a 32-bit system. float is a completely different binary format and is not compatible with c_int.

    You can use .argtypes to specify the parameter types and then pass values normally. Also .restype specifies the return value:

    lib.print_float.argtypes = c_float,c_double,c_longdouble
    lib.print_float.restype = None
    lib.print_float(1,2,3)