cTypes - передача строки в качестве указателя от python до c - PullRequest
0 голосов
/ 18 апреля 2020

Я пытаюсь передать строку (как указатель) из python в C функцию, используя cTypes.

Функция c должна получить указатель на строку (массив символов), но у меня не получилось успешно работать с несколькими символами, но мой единственный успех (вроде успешный, посмотрите на вывод) - это 1 символ, и я хотел бы получить некоторую помощь!

Мне нужно отправить указатель строки на символ - (без знака char * input)

My Python Код:

def printmeP(CHAR):
    print("In Print function")
    print(CHAR)
    c_sends = pointer(c_char_p(CHAR.encode('utf-8')))
    print("c_sends: ")
    print(c_sends[0])
    python_p_printme(c_sends)
    print("DONE function - Python")
    print(c_sends[0])
    return


from ctypes import c_double, c_int,c_char, c_wchar,c_char_p, c_wchar_p, pointer, POINTER,create_string_buffer,  byref, CDLL
import sys

lib_path = '/root/mbedtls/programs/test/mylib_linux.so' .format(sys.platform)


CHAR = "d"

try:
    mylib_lib = CDLL(lib_path)
except:
     print('STARTING...' )
python_p_printme = mylib_lib.printme
python_p_printme.restype = None
printmeP(CHAR)


My C Код:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void printme(char * param) {
    printf("\nStart c Function!\n");
    printf("%s\n Printing param\n ", param);
    char add = '!';
    strncat(param, &add, 1);

    printf("%s\n Printing param\n ", param);
    printf("Function Done - c\n");
}

Мой вывод:

In Print function
d <--- this is what i am sending
c_sends: 
b'd' <--- this is after encoding
��[� <-------------=|
 Printing param       |
 ��[�               | This is the c code print
 Printing param        | **Question:** Why does it print '�' and no what's supposed to be printed
 Function Done - c <--=|
DONE function - Python
b'd!' <--------------------- this is the last print that prints after the change.

Хотелось бы помочь, спасибо всем, кто принял участие:)

искренне, Роу

Ответы [ 2 ]

0 голосов
/ 19 апреля 2020

Существует ряд проблем:

  1. Определение .argtypes для ваших функций. Он будет ловить ошибки, передавая неверные параметры. Добавьте строку ниже и обратите внимание, что она множественного числа и является кортежем типов аргументов. Запятая содержит 1 кортеж:

    python_p_printme.argtypes = c_char_p,

  2. После внесения этого изменения вы получите ошибку, так как этот код:

    c_sends = pointer(c_char_p(CHAR.encode('utf-8')

    фактически отправляет C char** (указатель на c_char_p). После того, как вы правильно установили argtypes, вы можете просто вызвать функцию с байтовой строкой, и она будет работать. Ваша функция становится:

def printmeP(CHAR):
    print("In Print function")
    print(CHAR)
    python_p_printme(CHAR.encode())
    print("DONE function - Python")
Есть еще одна тонкая проблема. Хотя в этот момент может показаться, что программа работает Python строки являются неизменяемыми, поэтому, если вызываемая функция требует изменяемой строки, вы должны выделить изменяемый буфер, используя create_unicode_buffer (для w_char_p) или create_string_buffer (для c_char_p) ; в противном случае strcat в вашем коде C повредит строку Python.

Вот полный пример:

test. cpp

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// For Windows compatibility
#ifdef _WIN32
#   define API __declspec(dllexport)
#else
#   define API
#endif

// For C++ compiler compatibility
#ifdef __cplusplus
extern "C" {
#endif

API void alter_me(char* param, size_t length) {
    // truncates if additional info exceeds length
    strncat_s(param, length, " adding some info", length - 1);
}

#ifdef __cplusplus
}
#endif

test.py

from ctypes import *

lib = CDLL('./test')
alter_me = lib.alter_me
alter_me.argtypes = c_char_p,c_size_t
alter_me.restype = None

data = create_string_buffer(b'test',size=10)
alter_me(data,sizeof(data))
print(data.value)

data = create_string_buffer(b'test',size=50)
alter_me(data,sizeof(data))
print(data.value)

Вывод:

b'test addi'
b'test adding some info'

Обратите внимание, что вам не нужно использовать create_string_buffer, если функция C не изменяет буфер Например, параметр C равен const char*. Тогда вы можете просто позвонить printme(b'test string').

0 голосов
/ 18 апреля 2020

Вы можете использовать create_string_buffer.

Документацию можно найти здесь: https://docs.python.org/3/library/ctypes.html#ctypes .create_string_buffer

ctypes.create_string_buffer (init_or_size, size = None)

Это Функция создает изменяемый символьный буфер. Возвращаемый объект является массивом ctypes c_char.

init_or_size должен быть целым числом, которое указывает размер массива, или байтовым объектом, который будет использоваться для инициализации элементов массива.

С помощью buf.value.decode("utf-8") вы можете преобразовать буфер обратно в строку UTF-8 python.

Небольшой пример с вашей библиотекой кода C может выглядеть следующим образом:

from ctypes import *

mylib_lib = cdll.LoadLibrary("<your-lib>")
mylib_lib.printme.argtypes = c_char_p,

buf = create_string_buffer(128)
buf.value = b'Hello World'
mylib_lib.printme(buf)
print("print on python side:", buf.value.decode("utf-8"))

Будет выведено:

Start c Function!
Hello World
...
print on python side: Hello World!

на консоли.

...