ctypes странная обработка переменных аргументов в функциях - PullRequest
3 голосов
/ 25 октября 2019

Я запускаю этот фрагмент:

>>> 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 ожидает double для %f НО я думал, что числа с плавающей запятой получили двойные числа в функциях с переменными числами, как показывает следующий код C:

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

производит ожидаемое 1.000000 1.000000.

Я что-то упустил? Компилятор выполняет неявное приведение в коде C?

Я использую 64-битную машину.

1 Ответ

1 голос
/ 25 октября 2019

Звонящий отвечает за продвижение типа от float до double. Но ctypes ничего не знает о подписи printf, если вы не скажете это. Он не знает, что он вариативный, и что требуется продвижение типов.

Если вы не скажете ctypes, что такое подпись функции, установив argtypes и restype, она предполагает int тип возвращаемого значения, и тот параметр, который вы передали, соответствует сигнатурам. Так что в вашем случае он просто предполагает, что сигнатура printf:

int printf(char*, double, float)

Насколько я знаю, нет способа определить переменную argtypes в ctypes, но это не такпохоже, все равно выполняет кастинг, даже если установлен argtypes:

>>> 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
...