我有一个小的Python程序,需要从我的C共享库中调用一个函数:
首先使用C程序:
#include <stdio.h>
#include <stdlib.h>
void myprint(const char*, char**);
void myprint(const char* input, char** output)
{
printf("hello world\n");
printf("input string: %s\n",input);
*output = (char*) malloc(20);
sprintf(*output,"Life is cheap\n");
printf("output string in C program: %s\n",*output);
}
它被编译为共享库:
gcc -shared -Wl,-soname,testlib -o testlib.so -fPIC testlib.c
您会注意到该函数需要一个char指针到指针作为它的第二个参数。它将填充该参数,我希望调用它的python程序能够打印它。
我试图通过将引用传递给指针来从调用方python程序中实现这一点:
import ctypes
mem = POINTER( c_ubyte )()
testlib = ctypes.CDLL('/home/amanral/testlib.so')
testlib.myprint("hell with the world",byref(mem))
#print mem ===> This is where I want to print back the value filled by the C function
我知道print mem是错误的,因为它只打印:
<__main__.LP_c_ubyte object at 0x7f6460246560>
是否甚至可以打印出存储在内存中的实际字符串? 有更好的解决方案吗?
答案 0 :(得分:0)
通过在python程序中进行以下更改可以解决该问题:
add_action("admin_init", "custom_product_metabox");
function custom_product_metabox(){
add_meta_box("custom_product_metabox_01", "Product Description", "custom_product_metabox_field", "portfolio_page", "normal", "low");
}
function custom_product_metabox_field(){
global $page;
$data = get_post_custom($page->ID);
$val = isset($data['custom_product_input']) ? esc_attr($data['custom_product_input'][0]) : 'no value';
echo '<textarea rows="5" cols="220" name="custom_product_input" id="custom_product_input" value="'.$val.'"></textarea>';
}
add_action("save_post", "save_detail");
function save_detail(){
global $page;
if(define('DOING_AUTOSAVE') && DOING_AUTOSAVE){
return $page->ID;
}
update_post_meta($page->ID, "custom_product_input", $_POST["custom_product_input"]);
}
我的C库函数所需的char指针指向指针是通过使用以下方式实现的
import ctypes
from ctypes import *
plainText_pswd = "hellWithTheWorld"
encrypted_pswd = create_string_buffer(32)
testlib = ctypes.CDLL('/home/amanral/testlib.so')
testlib.myprint(plainText_pswd, pointer(pointer(encrypted_pswd)))
print "Recvd encrypted password in python program:" + encrypted_pswd.value
作为C函数的参数。我不确定这是否是正确的使用方式,但可以满足我的要求。我可以将C函数返回的值打印为pointer(pointer(encrypted_pswd))
仍然欢迎任何评论/建议。
答案 1 :(得分:0)
如果在Python中分配内存,则可以按照以下方法直接实现。请注意,我使用Python 3并显式传递字节字符串。
test.c
#include <stdio.h>
#include <stdlib.h>
#define API __declspec(dllexport) // Windows-specific export
API void myprint(const char* input, char* output)
{
printf("hello world\n");
printf("input string: %s\n",input);
sprintf(output,"Life is cheap\n");
printf("output string in C program: %s\n",output);
}
test.py
import ctypes
testlib = ctypes.CDLL('test')
mem = ctypes.create_string_buffer(32)
testlib.myprint(b'hell with the world',mem)
print(mem.value)
输出
hello world
input string: hell with the world
output string in C program: Life is cheap
b'Life is cheap\n'
如果您仍然想让C分配内存,那么如果您不想泄漏,就必须提供一个释放它的函数:
test.c
#include <stdio.h>
#include <stdlib.h>
#define API __declspec(dllexport) // Windows-specific export
API void myprint(const char* input, char** output)
{
printf("hello world\n");
printf("input string: %s\n",input);
*output = malloc(32);
printf("output address: %p\n",*output);
sprintf(*output,"Life is cheap\n");
printf("output string in C program: %s\n",*output);
}
API void myfree(char* mem)
{
printf("freeing %p\n",mem);
free(mem);
}
test.py
import ctypes
testlib = ctypes.CDLL('test')
# allocate a pointer to hold the result
mem = ctypes.c_char_p()
# Pass it by reference to be modified
testlib.myprint(b'hell with the world',ctypes.byref(mem))
print(mem.value)
testlib.myfree(mem)
输出
hello world
input string: hell with the world
output address: 0000028CEE9BAE50
output string in C program: Life is cheap
b'Life is cheap\n'
freeing 0000028CEE9BAE50