需要从Python传递指向C共享库函数的指针

时间:2018-07-04 17:02:11

标签: python c shared-libraries ctypes

我有一个小的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>

是否甚至可以打印出存储在内存中的实际字符串? 有更好的解决方案吗?

2 个答案:

答案 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