what is the best way to to convert c++ std::string to go string in cgo programing?

1,873 views
Skip to first unread message

hui zhang

unread,
Apr 18, 2017, 5:25:07 AM4/18/17
to golang-nuts
c code 
string getstring() {...}

go 

string gostr = ????(C.getstring())

Konstantin Khomoutov

unread,
Apr 18, 2017, 6:43:02 AM4/18/17
to hui zhang, golang-nuts

Konstantin Khomoutov

unread,
Apr 18, 2017, 6:44:59 AM4/18/17
to hui zhang, golang-nuts
On Tue, 18 Apr 2017 02:25:07 -0700 (PDT)
hui zhang <fastf...@gmail.com> wrote:

Oh, and note that std::string is a fat object.

So if getstring() really returns an instance of std::string,
and you need to actually extract its "raw bytes", you'd need to call
the c_str() method of std::string on that object before applying the
techniques from [1] to it.

1. https://github.com/golang/go/wiki/cgo#go-strings-and-c-strings

hui zhang

unread,
Apr 18, 2017, 9:09:03 PM4/18/17
to golang-nuts, fastf...@gmail.com
assume there is a c++ function   string getpath()

 you mean I should do this ?
 


char *CGetPath() {
auto str=getpath; 
char *c = malloc(str.length()), 
strcpy(c,str.c_str()); 
return c;
}
    

  p :=C.CGetPath()  
      gostr := C.GoString(
   C.free(p)



在 2017年4月18日星期二 UTC+8下午6:44:59,Konstantin Khomoutov写道:

Konstantin Khomoutov

unread,
Apr 19, 2017, 2:18:11 AM4/19/17
to hui zhang, golang-nuts
On Tue, 18 Apr 2017 18:09:03 -0700 (PDT)
hui zhang <fastf...@gmail.com> wrote:

> > > c code
> > > string getstring() {...}
> > > go
> > > string gostr = ????(C.getstring())
> > Oh, and note that std::string is a fat object.
> >
> > So if getstring() really returns an instance of std::string,
> > and you need to actually extract its "raw bytes", you'd need to
> > call the c_str() method of std::string on that object before
> > applying the techniques from [1] to it.
> >
> > 1. https://github.com/golang/go/wiki/cgo#go-strings-and-c-strings
> >
> assume there is a c++ function string getpath()
> you mean I should do this ?
>
> char *CGetPath() {
> > auto str=getpath;
> > char *c = malloc(str.length()),
> > strcpy(c,str.c_str());
> > return c;
> > }

I beleive there's no need to do malloc() and copy the bytes over:
c_str () is defined to return to you a pointer to a contiguous array of
NUL-terminated representation of the string maintained by the
std::string instance. So you do (untested):

char *CGetPath() {
return getpath().c_str();
}

and then in your Go code you do

p := C.GoString(C.GetPath())

2. http://en.cppreference.com/w/cpp/string/basic_string/c_str

hui zhang

unread,
Apr 19, 2017, 2:24:19 AM4/19/17
to Konstantin Khomoutov, golang-nuts
1)   getpath()  return a temp string,  its  c_str() pointer will be free out of function. So I use malloc
2)  Assume we use the malloc way ,  are  C.GoString()   copying the pointer memory ?  for we need C.free() malloc memory.

Konstantin Khomoutov

unread,
Apr 19, 2017, 2:44:03 AM4/19/17
to hui zhang, Konstantin Khomoutov, golang-nuts
On Wed, 19 Apr 2017 14:23:09 +0800
hui zhang <fastf...@gmail.com> wrote:

> 1) getpath() return a temp string, its c_str() pointer will be
> free out of function. So I use malloc

I'm not completely sure you're correct. C++ does not implement garbage
collection and the object on which you have called c_str() continues to
live on after getpath() returns. Now let's cite the manual on c_str():

| The pointer obtained from c_str() may be invalidated by:
| * Passing a non-const reference to the string to any standard library
| function, or
| * Calling non-const member functions on the string, excluding
| operator[], at(), front(), back(), begin(), rbegin(), end() and
| rend().

So I'd say in the sequence of calls I propose there's no chance of
anything quoted to happen -- basically the pointer returned by c_str()
gets passed to Go where C.GoString() copies the memory pointed to by it.

Things may break if you somehow concurrently call into your C++ side
and those calls may access the same std::string object we're talking
about. But if you do this, all bets are already off.

> 2) Assume we use the malloc way , are C.GoString() copying the
> pointer memory ? for we need C.free() malloc memory.

Yes, C.GoString() copies the memory.

Yes, you always need to free() what was malloc()ed for you -- because
you own the returned pointer.

hui zhang

unread,
Apr 19, 2017, 3:10:16 AM4/19/17
to Konstantin Khomoutov, golang-nuts
for  1) you mean 
char *CGetPath() {
    return getpath().c_str();
  }

this code will work ?

Frits van Bommel

unread,
Apr 19, 2017, 4:40:39 AM4/19/17
to golang-nuts, flat...@users.sourceforge.net
On Wednesday, April 19, 2017 at 9:10:16 AM UTC+2, hui zhang wrote:
for  1) you mean 
char *CGetPath() {
    return getpath().c_str();
  }

this code will work ?

That depends on whether getpath() returns a std::string or a (const) std::string& (a (const) reference). It will work if it returns a reference or const reference, but is not guaranteed to work if it doesn't (though it may appear to do so in some cases, or for some implementations of the C++ standard lib) because the standard lib is not required to use a reference-counted dynamic array. For example, it might instead choose to copy the array every time or to allocate small strings using an in-object buffer to avoid the overhead of dynamic allocation, and in both of those cases the return value of c_str() is no longer valid when the function returns.

Also, if do you need to copy the string in C++ code: strdup(getpath().c_str()) is better than malloc+strcpy (shorter and harder to get wrong). Case in point: your implementation malloc'ed str.length() bytes, failing to allocate an extra byte for the '\0' at the end.
Even better might be to call GoString(getpath().c_str()) in the CGetPath function to ensure only a single copy is made, but I'm not familiar enough with cgo to know if that's possible.

 

Frits van Bommel

unread,
Apr 20, 2017, 8:18:22 AM4/20/17
to hui zhang, golang-nuts
Please reply to the mailing list (use "reply all").

On Thu, Apr 20, 2017 at 4:39 AM, hui zhang <fastf...@gmail.com> wrote:
Thank you , I believe most function will return string  instead of string& 
I  test return string function ,   as expected it return the wrong value as the string is invalid out of function.

strdup is easier , thank you.

call GoString(getpath().c_str()) in the CGetPath function
Is that possible ?

Please refer to the end of that sentence, which you didn't quote: "but I'm not familiar enough with cgo to know if that's possible."
(This is why replying to the mailing list is better, someone there might be more familiar with cgo)

 

--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/u7EtqL9SKV4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Konstantin Khomoutov

unread,
Apr 22, 2017, 8:04:23 AM4/22/17
to Frits van Bommel, golang-nuts, flat...@users.sourceforge.net
On Wed, 19 Apr 2017 01:40:39 -0700 (PDT)
Frits van Bommel <fvbo...@gmail.com> wrote:

> On Wednesday, April 19, 2017 at 9:10:16 AM UTC+2, hui zhang wrote:
> >
> > for 1) you mean
> >>
> >> char *CGetPath() {
> >> return getpath().c_str();
> >> }
> >
> >
> > this code will work ?
> >
>
> That depends on whether getpath() returns a std::string or a (const)
> std::string& (a (const) reference). It will work if it returns a
> reference or const reference, but is not guaranteed to work if it
> doesn't (though it may appear to do so in some cases, or for some
> implementations of the C++ standard lib) because the standard lib is
> not required to use a reference-counted dynamic array. For example,
> it might instead choose to copy the array every time or to allocate
> small strings using an in-object buffer to avoid the overhead of
> dynamic allocation, and in both of those cases the return value of
> c_str() is no longer valid when the function returns.

I think that [1] guarantees that it's perfectly OK to return the value
returned by c_str() from a function unless the object we've called
c_str() on gets destructed upon that return (i.e. it was an automatic
or "RAII-d" variable in that function). That is, if the OP can
guarantee that the std::string object being discussed was live at the
time getpath() was called and is live after that call was finished,
it's fine to use whatever c_str() returned.

To cite [1] once again:

| The pointer obtained from c_str() may be invalidated by:
| * Passing a non-const reference to the string to any standard library
| function, or
| * Calling non-const member functions on the string, excluding
| operator[], at(), front(), back(), begin(), rbegin(), end() and
| rend().

> Even better might be to call GoString(getpath().c_str()) in
> the CGetPath function to ensure only a single copy is made, but I'm
> not familiar enough with cgo to know if that's possible.

Unfortunately, that's not possible: cgo can be thought of as providing
some sort of API for both sides -- the C's and the Go's and allowing
them both to interact via those APIs. It's impossible to arbitrarily
mix and match C and Go sides in expressions, so you'll have to arm your
C side with a function which would do getpath().c_str() and call it to
produce an input value for GoString(). But this actually changes
nothing in the semantics in this particular case -- see above.

1. http://en.cppreference.com/w/cpp/string/basic_string/c_str
Reply all
Reply to author
Forward
0 new messages