Этот способ получается:Olej писал(а): 5-м вариантом есть использование модуля ctypes из стандартной библиотеки модулей Python (/usr/lib/python2.7).
а). самым простым по реализации (написанию кода, технике сборки, не требует никаких дополнительных инструментов и т.д.)
б). самым опасным с точки зрения возможных ошибок: на стыке Python-C отсутствует не только какой-либо контроль правильности соответствия типов ожидаемых параметров, но даже просто их количества!
Вот пример нескольких вызовов, показывающих простоту реализации:
- файл C-реализации модуля call.c - 3 разных функции, с разным числом и типом параметров и разным возвращаемым значением:
Код: Выделить всё
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <locale.h>
#include <wchar.h>
// c_double fun1( c_short )
double fun1( short i ) {
printf( "получен параметр = %d\n", i );
return (double)i;
}
// c_void_p fun2( c_char_p )
const char* fun2( const char* s ) {
printf( "локализация операционной системы: %s\n",
setlocale( LC_ALL, "" ) ); // по умолчанию, из установок системы
int nsym = 0;
const char *p = s;
while( 1 ) {
int n = mblen( p, MB_CUR_MAX );
if( 0 == n ) break;
nsym++;
p += n;
};
printf( "получен параметр [ mbchar* ] : \"%s\"; длина: в байтах = %d, в символах = %d\n",
s, strlen( s ), nsym );
static const char* ret = "возвращаемая строка";
return ret;
}
// c_void_p fun3( c_float, c_long, c_char_p )
void* fun3( float f, long l, char* s ) {
printf( "вызов функции 3-х переменных: \"float\"=%f, \"long\"=%ld, \"char*\"=\"%s\"\n",
f, l, s );
return (void*)s;
}
- сборка:
Код: Выделить всё
bash-4.2$ gcc -shared -o call.so -fPIC call.c
Код: Выделить всё
#!/usr/bin/python
# -*- coding: utf-8 -*-
import ctypes
lib = ctypes.CDLL( './call.so' )
print '-----------------------------------------------------'
# === double fun1( short ) ===
# pfun = ctypes.CDLL( './call.so' ).fun1
pfun = lib.fun1
pfun.restype = ctypes.c_double
pfun.argtypes = ( ctypes.c_short, )
x = pfun( 3 )
print 'возвращено значение %f' % x
print '-----------------------------------------------------'
# === const char* fun2( const char* ) ===
#pfun = ctypes.CDLL( './call.so' ).fun2
pfun = lib.fun2
pfun.restype = ctypes.c_char_p
pfun.argtypes = ( ctypes.c_char_p, )
x = pfun( "строка вызова" )
print 'возвращено значение : "%s"' % x
print '-----------------------------------------------------'
# === void* fun3( float, long, char* ) ===
pfun = lib.fun3
pfun.restype = ctypes.c_void_p
pfun.argtypes = ( ctypes.c_float, ctypes.c_long, ctypes.c_char_p )
s = "строка"
x = pfun( 3.1415, -12345, s )
print 'возвращено значение\t= %x' % x
print 'id( строка-параметр )\t= %x' % id( s )
print '-----------------------------------------------------'
Код: Выделить всё
bash-4.2$ python test.py
-----------------------------------------------------
получен параметр = 3
возвращено значение 3.000000
-----------------------------------------------------
локализация операционной системы: ru_RU.UTF-8
получен параметр [ mbchar* ] : "строка вызова"; длина: в байтах = 25, в символах = 13
возвращено значение : "возвращаемая строка"
-----------------------------------------------------
вызов функции 3-х переменных: "float"=3,141500, "long"=-12345, "char*"="строка"
возвращено значение = b76815ac
id( строка-параметр ) = b7681598
-----------------------------------------------------
И он же показывает в чём опасность: можно вполне благополучно в C-параметр char* передавать значение floaf, а возвращённый из C-кода указатель void* толковать в Python коде как long...