constant string parameters passed by reference

608 views
Skip to first unread message

ptao

unread,
Nov 8, 2010, 6:44:15 PM11/8/10
to cython-users
Hi, I'm trying to wrap a few functions which use constant strings
passed by reference. I'm getting an error during compilation of the
generated C code. Here are the relevant code portions:

// user.h
int get_avatar_name(const std::string & id, std::string &result);

# cuserconfig.pxd
int get_avatar_name(string id, string result)

# userconfig.pyx
def get_avatar_name(self, id):
cdef string *result_strp = new string()
retval = self.ptr.get_avatar_name(cstrToStr(id),
result_strp[0])
result = strToCstr(result_strp[0])
del result_strp
return retval, result

cdef string cstrToStr(char *cstr):
return <string>cstr

cdef char *strToCstr(string str):
cdef char *cstr = <char *>malloc(str.length() + 1)
strcpy(cstr, str.c_str())
return cstr



I get the following error messages:
../userconfig.cpp:5385: error: no matching function for call to
'User::get_avatar_name(std::string, std::string)'
../../../../../../../include/libuserconfig/user.h:249: note:
candidates are: int User::get_avatar_name(const std::string&,
std::string&)



So what is the right way to wrap this function? Also, is there a
better way of converting between char[] strings and std::string?

Robert Bradshaw

unread,
Nov 8, 2010, 6:51:37 PM11/8/10
to cython...@googlegroups.com

I think your issue is with constness, not references. Cython doesn't
yet have any support for const (which is a mess). Probably the easiest
is to write a simple utility function that converts from std::string
to const std::string, or references thereof.

- Robert

ptao

unread,
Nov 8, 2010, 7:14:31 PM11/8/10
to cython-users
I can't touch the C++ code, so would it be possible to write something
like that in Cython?

On Nov 8, 3:51 pm, Robert Bradshaw <rober...@math.washington.edu>
wrote:

Robert Bradshaw

unread,
Nov 8, 2010, 7:17:58 PM11/8/10
to cython...@googlegroups.com
On Mon, Nov 8, 2010 at 4:14 PM, ptao <phill...@gmail.com> wrote:
> I can't touch the C++ code, so would it be possible to write something
> like that in Cython?

Alas, if you could easily write something like this in Cython, you
wouldn't need to be writing int ;).

What I would do is write a C++ file util.cpp with the necessary
functions, and then do

cdef extern from "util.cpp":
...

It is possible to do such a thing in Cython itself, using cnames (see
the old C++ wrapping guides for how this works...)

- Robert

Paul Connell

unread,
Nov 9, 2010, 4:49:58 AM11/9/10
to cython...@googlegroups.com

Hi,

I have come up with this:

#cuserconfig.pxd

cdef extern from "user.h":
ctypedef char *stdstringr "const std::string&"
cdef cppclass stringclass "std::string":
void stringclass()
char *c_str()
int get_avatar_name(stdstringr id, stringclass result)

#userconfig.pyx

cimport cuserconfig as C

def get_avatar_name(char *input):
cdef C.stringclass s = C.stringclass()
cdef int ret = C.get_avatar_name(input, s)
return ret, s.c_str()

I made a toy implementation of get_avatar_name() to test with:

//user.cpp

int get_avatar_name(const std::string & id, std::string &result)

{
static std::string s("hello world");
printf("%s\n", id.c_str());
result = s;
return 7;
}

and...


Python 2.6.5 (r265:79063, Jun 12 2010, 17:07:01)
[GCC 4.3.4 20090804 (release) 1] on cygwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from userconfig import *
>>> results = get_avatar_name("cython")
cython
>>> print results
(7, 'hello world')
>>>

I have found myself using this sort of pattern a few times myself

ctypedef char *stdstringr "const std::string&"

which allows Cython to produce code that works based on the underlying
type's ability to implicitly construct/coerce, along with the
apparently standard Cython practice of passing by value where a
reference is actually the function's argument signature, and adding
the constness even though Cython doesn't understand const.

This might not be a complete solution for you I realise, but is this
idea any help?

Paul

ptao

unread,
Nov 11, 2010, 9:12:20 PM11/11/10
to cython-users
Hey Paul,

That worked perfectly.

Thanks.

On Nov 9, 1:49 am, Paul Connell <paulconne...@gmail.com> wrote:

Paul Connell

unread,
Nov 12, 2010, 4:10:25 AM11/12/10
to cython...@googlegroups.com
On Fri, Nov 12, 2010 at 2:12 AM, ptao <phill...@gmail.com> wrote:
> Hey Paul,
>
> That worked perfectly.
>
> Thanks.

You're welcome. I'm glad it worked out for you, and I do use the same
technique myself in some code that will soon move from prototye to
production. However, it's effectively telling Cython a little white
lie, and I am a little bit uncomfortable with it.

ctypedef char *stdstringr "const std::string&"

Translates to: "A const std:string reference is a non-const char
pointer". Patently not true, even though it tricks the generated code
into working very nicely and allows for terse and elegant (imho)
Cython code.

It makes Cython a little bit less opaque, and we start to write Cython
code with foreknowledge of what C code the compiler will produce. It
sounds like the kind of thing that might break in a future revision.
Nevertheless it's such a useful feature to be able to exploit, that
I'd be interested to hear a Cython developer's take on it.

On a slightly related note, since this technique relies on implicit
type coercions, I have seen in some of the generated C code that a lot
casts are used, and that they are always plain C-style ones. Would it
be an easy change to the code to have these produced as static_cast
(perhaps optionally dynamic_cast) when --cplus mode is used? I have
had occasional run-time errors, I'm pretty sure, that were to do with
forced type coercions that must have ended up as a reinterpret_cast
type of operation at run time. If these could be made C++-style with
--cplus enabled, the compiler might be able to spot problems and issue
errors or warnings.

Paul

Reply all
Reply to author
Forward
0 new messages