вызывающие функции возвращаются как указатели от других функций в ctypes - PullRequest
2 голосов
/ 23 сентября 2011

Я пытаюсь использовать ctypes для вызова функции c, которая была возвращена как указатель из другой функции. Из документации видно, что я могу сделать это, объявив функцию с CFUNCTYPE, а затем создав экземпляр с помощью указателя. Это, однако, кажется, дает мне ошибку. Вот пример кода.

sample.c:

#include <stdio.h>

unsigned long long simple(void *ptr)
{
  printf("pointer = %p\n", ptr);
  return (unsigned long long)ptr;
}

void *foo()
{
  return (void *)simple;
}

unsigned long long (*bar)(void *ptr) = simple;

int main() 
{
  bar(foo());
  simple(foo());
}

и simple.py:

from ctypes import *
import pdb

_lib = cdll.LoadLibrary('./simple.so')

_simple = _lib.simple
_simple.restype = c_longlong
_simple.argtypes = [ c_void_p ]

_foo = _lib.foo
_bar = CFUNCTYPE(c_int, c_void_p)(_foo())

pdb.set_trace()
_bar(_foo())

Вот сеанс gdb / pdb:

(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /usr/bin/python simple.py
[Thread debugging using libthread_db enabled]
> .../simple.py(15)<module>()
-> _bar(_foo())
(Pdb) p _foo()
-161909044
(Pdb) cast(_bar,c_void_p).value
18446744073547642572L
(Pdb) _simple(_foo())
pointer = 0xfffffffff65976cc
-161909044
(Pdb) int('fffffffff65976cc',16)
18446744073547642572L

Любопытно, что если я запускаю с использованием главной функции C, я получаю

$ ./simple
pointer = 0x400524
pointer = 0x400524

, который не совпадает с указателем, который я получаю из кода Python.

Что я здесь не так делаю?

Заранее благодарим за любые указания, которые вы можете дать!

1 Ответ

2 голосов
/ 24 сентября 2011

Вы не определяете тип возврата для _foo, попробуйте добавить:

_foo.restype = c_void_p

Для ctypes по умолчанию задано int returntype, и оно выглядит (из приведенного в сеансе pdb преобразования), как будто вы работаете в 64-битной системе, что означает, что ваш указатель будет усечен при преобразовании в int. В моей системе код работает, но это 32-разрядная система (и, к сожалению, сейчас у меня нет 64-разрядной системы для тестирования).

Кроме того, определение _bar на самом деле не соответствует тому, что есть в коде C, я предлагаю использовать что-то вроде:

_bar = CFUNCTYPE(c_longlong, c_void_p).in_dll(_lib, "bar")
...