Необходимо передать указатель на указатель на функцию общего lib C из Python - PullRequest
0 голосов
/ 04 июля 2018

У меня есть небольшая программа на 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

Как вы заметили, функция нуждается в указателе на указатель на символ в качестве второго аргумента. Он заполнит этот аргумент, и я ожидаю, что вызывающая его программа 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 голосов
/ 06 июля 2018

Если вы выделите память в 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
0 голосов
/ 05 июля 2018

Проблема решается путем внесения следующих изменений в программу Python:

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, достигается с помощью pointer(pointer(encrypted_pswd)) в качестве аргумента функции C. Я не уверен, что это правильный способ использования, но он подходит для моего требования. Я могу напечатать значение, возвращаемое функцией C как encrypted_pswd.value

Любые комментарии / предложения по-прежнему приветствуются.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...