Which string type is faster for ctypes

Hi all,
I am writing a gui library for python in Odin. Odin is a C like language with manual memory management. I tested some string functions. b"Python string" is working with c_char_p and "Python wide string" is working with c_wchar_p. I would like to know which one is faster ? In Odin, I can convert the c_char_p into a wchar pointer, but if ctypes can do it, it is good for me.
And I have a second question. Ctypes will convert python strings toc_char_p or c_wchar_p automatically, But does this happen vice versa ? I mean, if I return a c_char_p or a c_wchar_p from an Odin function, does ctypes convert it to python string ?

For a string that is shown to humans you must support the python string type which is unicode.

A gui cannot use bytes as that would require users of your library to always encode from unicode to some byte encoding. Further inside your library you would need to decode from bytes into Unicode for displaying the text.

So string is fastest.

1 Like

Thanks for the reply. Basically, I don’t like the fact that we need to type a ‘b’ every string literal when we use c_char_p. I like the straight forward way.

Rather than using ctypes – which may add considerable overhead – you might consider using Cython to convert Python strings into C strings or vice-versa. See: Unicode and passing strings — Cython 3.1.0a0 documentation

2 Likes

If you prefer a more straightforward approach without having to include the ‘b’ prefix for string literals, you can use c_wchar_p for all your strings, regardless of character encoding. While this may result in slightly larger memory consumption due to the nature of wide-character strings, it provides a uniform and convenient way to handle strings in your Odin GUI library.

1 Like

You could use a pure python facade that does the Unicode encode/decode of strings into bytes to pass though your code via ctypes.

2 Likes

@hansgeunsmeyer
Thanks for the reply. Well, I spent a lot of time to benchmark pure cpython, cython, pybind11 and cffi. Among them the winner is pure cpython with ctypes. I think, converting python objects to and from foreign language is the cause of the delay. In my tests, ctypes has 2x speed than cython. It’s good to know about the backgrounds of my project. I am doing a gui library project with windows api functions. So most of the time, execution is happening over c functions. And there are plenty of times python needs to call these functions. So the parameter conversion is taking the toll. A simple window with two buttons in pybind took 75-100 ms. The same in cython took 55-70 ms. In ctypes with pure python, it is almost same of cython. But if I use Odin for all the heavy lifting, I can reduce the speed to almost 10-12 ms. Then I tested the same odin dll with cython. The speed went to 20-25 ms.

EDIT : I forgot to mention the speed of CFFI. It is performing very well but in “API-out of line” mode, it has the same speed of cython. I did test it with some C code which is creating a window and buttons. But I checked my Odin dll with cffi also. That was in “ABI-out of line” mode. It runs almost near to cpython with ctypes speed. But if something seems similar, I would vote for ease of use, and that’s ctypes. I have a gui lib in pure python with ctypes already. But I think, by using odin dll, I can make some serious speed differences.

How significant are the timings here? It’s irrelevant for one thing to be twice the speed of another if even the slower option is so fast that nobody would notice the difference. You’re writing a GUI library here - a tenth of a second still feels pretty responsive, and anything under a hundredth of a second is pretty much equivalent to zero time. How long does it take to use cython?

@Rosuav
These are the timings from different projects. (One window + 2 buttons - average of 5 runs)
CPython + ctypes = 58 ms
Cython = 55 ms
Odin dll + CPython + ctypes = 17 ms

@AhanaSharma
Yeah, that’s what I am using now. I can use a wchar pointer in odin and ctypes will convert a regular python string if I use c_wchar_p. By using this, I don’t have the burden to allocate memory and convert the string. The one and only draw back I see in this method is, in case If I need the python string after the function exits, I need to allocate memory and copy the content of c_wchar_p parameter of the function. I think the same would be true in case I use c_char_p. But if I use c_char_p, I need to convert the c_char_p into wchar_t* in odin, because windows functions needs that.

1 Like

wchar is only a Windows thing really. Wil your GUI not work on mac or linux?

@barry-scott
My GUI lib is based on the windows API. So it only works on Windows.