wecx
wecx

Reputation: 402

ctypes weird handling of variadic arguments in functions

I am launching this snippet:

>>> from ctypes import *
>>> libc = CDLL("libc.so.6")
>>> libc.printf("%f %f\n", c_float(1.0), c_double(1.0))
0.000000 1.000000

printf expects a double for %f BUT I thought floats got promoted to doubles in variadic functions, as the following C code shows:

#include<stdio.h>
int main()
{
   float a = 1.0f;
   double b = 1.0;
   printf("%f %f\n", a, b);
}

produces the expected 1.000000 1.000000.

Am I missing something? Is the compiler doing some implicit casting in the C code?

I am using a 64-bits machine.

Upvotes: 3

Views: 508

Answers (1)

JBGreen
JBGreen

Reputation: 544

The caller is responsible for doing the type promotion from float to double. But ctypes doesn't know anything about the signature of printf unless you tell it. It doesn't know it's variadic and that type promotion is required.

If you don't tell ctypes what the signature of a function is by setting argtypes and restype, it assumes a int return type, and that whatever parameter you passed in match the signatures. So in your case it just assumes the signature of printf is:

int printf(char*, double, float)

As far as I know there is no way to define a variadic argtypes in ctypes, but it doesn't seem to do casting anyway, even if argtypes is set:

>>> from ctypes import *
>>> libc = CDLL("libc.so.6")
>>> libc.printf.argtypes = [c_char_p, c_double, c_double]
>>> libc.printf(c_char_p(b"%f %f\n"), c_double(1.0), c_float(1.0))
Traceback (most recent call last):
  File "printf.py", line 5, in <module>
    libc.printf(c_char_p(b"%f %f\n"), c_double(1.0), c_float(1.0))
ctypes.ArgumentError: argument 3: <class 'TypeError'>: wrong type

Upvotes: 1

Related Questions