Как передать указатель String-Array в функцию, используя Ctypes? - PullRequest
0 голосов
/ 26 апреля 2020

У меня есть C функция этой подписи:

void updateCaseFile( char scalarFields[][100], uint nscalars, char vectorFields[][100], uint nvectors, uint* timeList, uint ntimes );

Что в моем конкретном случае, в C, я передаю:

char scfields[2][100] = {"rho", "T"};

char vfields[1][100] = {"U"};

updateCaseFile(scfields, 2, vfields, 1, timeList, nwrite);

В Linux В системе я хочу передать scfields и vfields из Python, используя ctypes, поэтому я использую ctypes.c_char_p в качестве следующего:

import ctypes

libbio = ctypes.CDLL('/home/lib/libio.so')

updateCaseFile = libbio.updateCaseFile

scfields = ["rho" , "T" ]

scfields_array = (ctypes.c_char_p * (len(scfields)+1))()

vfields = ["U"]

vfields_array = (ctypes.c_char_p * (len(vfields)+1))()

updateCaseFile(scfields, 2, vfields, 1, timeList, nwrite)

Но я получаю эту ошибку:

ArgumentError: аргумент 1:: не знаю, как преобразовать параметр 1

Измените код, используя numpy

import numpy as np

scfields = np.chararray((1, 2))

scfields = ('rho' , 'T' )

vfields = np.chararray((1, 1))

vfields = ('U')

scfields_p = scfields.ctypes.data_as(c_wchar_p)

vfields_p = vfields.ctypes.data_as(c_wchar_p)

updateCaseFile(scfields, 2, vfields, 1, timeList, nwrite)

И я снова получаю эту ошибку:

ArgumentError: аргумент 1:: Не знаю, как преобразовать параметр 1

Я знаю, какие во втором случае scfields конвертируют в кортеж, но я не могу найти, что не так. Как решить эту проблему?

Спасибо

1 Ответ

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

Вы создаете массивы char *, а не двумерные массивы. Вот способ инициализировать правильные массивы. Также обратите внимание, что определение .argtypes и .restype помогает вам при проверке ошибок ctypes:

from ctypes import *

dll = CDLL('./test')
dll.updateCaseFile.argtypes = POINTER(c_char * 100),c_uint,POINTER(c_char * 100),c_uint,POINTER(c_uint),c_uint
dll.updateCaseFile.restype = None

A = c_char * 100  # make a name for the char[100] type.

# This is *not* fast.  Use a numpy array if you need speed
def make(*args):
    a = (A * len(args))()          # create a[n][100] array
    for i,arg in enumerate(args):  # initialize each element
        a[i].value = arg.encode()  # encode for byte strings.  Alternatively, pass bytes strings.
    return a

scfields = make('Rho','T')
vfields = make('U')
timeList = (c_uint * 2)(1,2)
dll.updateCaseFile(scfields,2,vfields,1,timeList,2)

С этой демонстрацией C DLL:

#include <stdio.h>

typedef unsigned int uint;

__declspec(dllexport) void updateCaseFile( char scalarFields[][100], uint nscalars, char vectorFields[][100], uint nvectors, uint* timeList, uint ntimes )
{
    for(uint i = 0; i < nscalars; ++i)
        printf("%u: %s\n",i,scalarFields[i]);
    for(uint i = 0; i < nvectors; ++i)
        printf("%u: %s\n",i,vectorFields[i]);
    for(uint i = 0; i < ntimes; ++i)
        printf("%u: %u\n",i,timeList[i]);
}

Вывод:

0: Rho
1: T
0: U
0: 1
1: 2
...