Передача списка строк из python / ctypes в функцию C, ожидающую символ ** - PullRequest
19 голосов
/ 16 августа 2010

У меня есть функция C, которая ожидает список \ 0 завершенных строк в качестве ввода:

void external_C( int length , const char ** string_list) { 
   // Inspect the content of string_list - but not modify it.
} 

Из python (с ctypes) Я хотел бы вызвать эту функцию на основе списка строк Python:

def call_c( string_list ):
    lib.external_C( ?? )

call_c( ["String1" , "String2" , "The last string"])

Какие-нибудь советы о том, как создать структуру данных на стороне Python? Заметьте, что я гарантирую, что функция C НЕ будет изменять содержимое строк в string_list.

Привет

Йоаким

Ответы [ 4 ]

25 голосов
/ 16 августа 2010
def call_c(L):
    arr = (ctypes.c_char_p * len(L))()
    arr[:] = L
    lib.external_C(len(L), arr)
5 голосов
/ 16 августа 2010

Большое спасибо; это работало как очарование. Я также сделал альтернативный вариант, как это:

def call_c( L ):
    arr = (ctypes.c_char_p * (len(L) + 1))()
    arr[:-1] = L
    arr[ len(L) ] = None
    lib.external_C( arr )

И затем в C-функции я перебирал список (char **), пока не нашел NULL.

1 голос
/ 08 декабря 2018

Использование ctypes

создание списка истечений (строк)

expiries = ["1M", "2M", "3M", "6M","9M", "1Y", "2Y", "3Y","4Y", "5Y", "6Y", "7Y","8Y", "9Y", "10Y", "11Y","12Y", "15Y", "20Y", "25Y", "30Y"]

Логика для отправки массива строк

преобразование массива строк в байтовый массив с помощью цикла в массиве

 expiries_bytes = []
    for i in range(len(expiries)):
        expiries_bytes.append(bytes(expiries[i], 'utf-8'))

Логические ctypes для инициации указателя с длиной массива

expiries_array = (ctypes.c_char_p * (len(expiries_bytes)+1))()

назначение байтового массива в указатель

expiries_array[:-1] = expiries_bytes
1 голос
/ 27 декабря 2015

Я просто делаю это, используя карту типов SWIG

1. запишите настроенную карту типов в demo.i файле интерфейса.

%module demo

/* tell SWIG to treat char ** as a list of strings */
%typemap(in) char ** {
    // check if is a list
    if(PyList_Check($input))
    {
        int size = PyList_Size($input);
        int i = 0;
        $1 = (char **)malloc((size + 1)*sizeof(char *));
        for(i = 0; i < size; i++)
        {
            PyObject * o = PyList_GetItem($input, i);
            if(PyString_Check(o))
                $1[i] = PyString_AsString(o);
            else
            {
                PyErr_SetString(PyExc_TypeError, "list must contain strings");
                free($1);
                return NULL;
            }
        }
    }
    else
    {
        PyErr_SetString(PyExc_TypeError, "not a list");
        return NULL;
    }
}

// clean up the char ** array
%typemap(freearg) char ** {
    free((char *) $1);
}

2. Генерация расширения

$ swig -python demo.i  // generate wrap code
$ gcc -c -fpic demo.c demo_wrap.c
$ gcc -shared demo.o demo_wrap.o -o _demo.so

3. импорт модуля в python.

>>> from demo import yourfunction
...