I have libx.so, and it exports a function and a global char *,
char *c_ptr = 0;
void foo(char *s)
{
c_ptr = s;
}
In python, I pass a str to foo in 2 ways,
>>>libx = ctypes.CDLL("./libx.so")
#pass a raw str
>>>libx.foo("string")
#pass a c_char_p object
>>>libx.foo(c_char_p("strng"))
Q
1.I think, libx.foo("string") passes a Python str object to a C function which will later assign the string to char *c_ptr. I wonder, will c_ptr points to the str object "string" after the call foo? Cuz I presume the str object "string" will be garbage-collected after the call to foo, right?
2.Are the 2 ways (passing "string" and c_char_p("string")) difference in effect?
Are they different in effect?
1: What is Happening
ctypes does adapt the Python string, correctly guessing that the function takes a
char*. Effectively,libx.foo("string")is equivalent to the second examplelibx.foo(c_char_p("string"))with a little runtime adaptation.Your intuition about the string being garbage collected shortly after the call is correct. Nothing in Python retains a reference to the adapted c_char_p view of the string, and thus it will be returned to the object pool — likely to be re-issued in the future. Which means that the
char* c_ptrwill probably point at junk very soon.2: Different in Effect
The second form allows you to keep a reference to the view passed to the C function. If you changed the example slightly:
Then as long as a reference is maintained to
s, thec_ptrvalue will be valid. You could accomplish that by just keeping a reference in the module implementing your binding to libx.