2

I'm working with a closed source shared library with example code in C++ like so:

// Header
#define MAX_PARAM_NAME             10
int foo(..., char **ParNameList, ...);

// Main
char      *ParNameList = (char *)NULL;
ret = foo(..., &ParNameList,...);
par = (char (*)[MAX_PARAM_NAME])ParNameList;

How should it be handled in ctypes?

The problematic part is that in function declaration foo(..., char **ParNameList, ...); a char ** is expected, but a reference to char * is actually given in the function call.

So far I have:

from ctypes import *
so = cdll.LoadLibrary(...)  
so.foo.argtypes = [                                                                  
...
POINTER(POINTER(c_char)), # ParNameList                       
...
]                                                                                                        
so.foo.restype = c_int                                                               

#...
ParNameList = POINTER(c_char)()
so.foo(..., ParNameList ,...)

which gives me a garbage string, where I see the required output is interleaved with random changing RAM bits.

But how does (char (*)[MAX_PARAM_NAME]) cast work in ctypes?

If there is a more straight forward way for the whole thing, I'd appreciate to hear it.

2
  • Possible duplicate of Python Ctypes passing pointer for data Commented Jun 22, 2018 at 12:08
  • I think this is a slightly different case, the problem is in ambiguity of char ** as per function definition and char * in C-Code. In the C-Example the array of char pointers needs to be decomposed after the function call. Commented Jun 22, 2018 at 12:27

2 Answers 2

1

You'd need to pass the address of the c_char pointer using byref:

foo.argtypes = [..., POINTER(POINTER(c_char)), ...]
foo.restype = c_int

par_name_list = POINTER(c_char)()

# pass by reference
foo(byref(par_name_list))

par = cast(par_name_list, POINTER(c_char * MAX_PARAM_NAME))

You may need to free the memory afterwards.

Sign up to request clarification or add additional context in comments.

6 Comments

ctypes-relevant and strange part is the cast of pointer to const length array: (char (*)[MAX_PARAM_NAME])ParNameList;
I think it'd just be par = cast(par_name_list, POINTER(c_char) * MAX_PARAM_NAME).
actually POINTER(c_char *MAX_PARAM_NAME) works! full line: print [(cast(par_name_list, POINTER(c_char*MAX_PARAM_NAME) ))[i].value for i in range(ParNumber)]
Well there you go :)
Also, on second thought you'd probably want to use create_string_buffer() instead of POINTER(c_char)() to create a mutable string to pass to foo as it's more idiomatic.
|
0

There is pythonic workaround, which I'd like to share for completeness, it's not nice, but it works.

# ParNumber is known, ParNameList is a string
pars = []                                                                                          
for i in range(ParNumber):                                                                        
    q = ParNameList[i*10:i*10+10]                                                                      
    q = q[:q.index('\0')]                                                                          
    print q                                                                                        
    pars.append(q)    

still would like to know, what is the better way

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.