digitalmars.D - Passing string from D to c++
- Milvakili (5/5) Jul 30 2013 I'm linking D with C++ lib.a file. When the C++ function has
- Dicebot (2/7) Jul 30 2013 http://dlang.org/phobos/std_string.html#.toStringz
- Milvakili (2/10) Jul 30 2013 So I need to pass them as char*, I can not pass them as string?
- John Colvin (4/15) Jul 30 2013 Correct.
- Milvakili (6/23) Jul 30 2013 Thanks. Is there any work in progress related to string passing?
- Dicebot (3/9) Jul 30 2013 c_function(toStringz("hello").ptr) does not seem that bad, what
- monarch_dodra (16/27) Jul 31 2013 I want to point out that one of the dangers (as I've heard it, I
- deadalnix (15/30) Jul 31 2013 You have to work very hard to not find it either in the stack or
- monarch_dodra (6/38) Jul 31 2013 I'll take your word for it then. As I said, I didn't run into
- John Colvin (40/67) Jul 30 2013 I had a crack at making this work, but I'm stuck on some basics
- Walter Bright (3/9) Jul 30 2013 You might want to look at the name mangling of the D printString vs the ...
- John Colvin (12/22) Jul 31 2013 Woops, yeah that was never going to work.
- Dicebot (3/5) Jul 31 2013 Maybe http://d.puremagic.com/issues/show_bug.cgi?id=10077 can
- John Colvin (2/7) Jul 31 2013 Yikes that's quite a rabbit hole, it's all a bit beyond me tbh.
- Adam D. Ruppe (12/13) Jul 30 2013 I would pass it as a char* and a size_t for length.
- Jesse Phillips (6/7) Jul 30 2013 C++ doesn't have an immutable(char)[], it has char* and its own
- deadalnix (2/9) Jul 30 2013 const char*, char const* are equivalent to const(char)* in D.
- Jesse Phillips (5/17) Jul 30 2013 I was referring to string types:
- deadalnix (3/21) Jul 31 2013 In C++, std::string own its own copy of the string. So it is safe
- Jesse Phillips (4/6) Jul 31 2013 I thought the discussion was about:
- JS (9/20) Jul 30 2013 You can't pass them as string because they have different
- bsd (4/4) Jul 30 2013 I'm using toStringz() and it works fine if you're c++ function
- bsd (13/13) Jul 30 2013 (damn, no edit!)
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (6/9) Jul 30 2013 I think the OP means std::string, which also is not zero-terminated. (On...
- monarch_dodra (10/15) Jul 31 2013 You can obtain a 0 terminated "const char*" from an std::string
- deadalnix (9/14) Jul 30 2013 When it come to C++, passing via C string is always an option,
I'm linking D with C++ lib.a file. When the C++ function has compatible data types I can call them from D. But when I changed the parameter to string I got bunch of errors. Data Type Compatibility table does not include strings. Is there a way of passing strings?
Jul 30 2013
On Tuesday, 30 July 2013 at 19:52:44 UTC, Milvakili wrote:I'm linking D with C++ lib.a file. When the C++ function has compatible data types I can call them from D. But when I changed the parameter to string I got bunch of errors. Data Type Compatibility table does not include strings. Is there a way of passing strings?
Jul 30 2013
On Tuesday, 30 July 2013 at 20:02:51 UTC, Dicebot wrote:On Tuesday, 30 July 2013 at 19:52:44 UTC, Milvakili wrote:So I need to pass them as char*, I can not pass them as string?I'm linking D with C++ lib.a file. When the C++ function has compatible data types I can call them from D. But when I changed the parameter to string I got bunch of errors. Data Type Compatibility table does not include strings. Is there a way of passing strings?
Jul 30 2013
On Tuesday, 30 July 2013 at 20:09:01 UTC, Milvakili wrote:On Tuesday, 30 July 2013 at 20:02:51 UTC, Dicebot wrote:Correct. Just thinking off the top of my head: you could probably hack something together though with a struct and casting.On Tuesday, 30 July 2013 at 19:52:44 UTC, Milvakili wrote:So I need to pass them as char*, I can not pass them as string?I'm linking D with C++ lib.a file. When the C++ function has compatible data types I can call them from D. But when I changed the parameter to string I got bunch of errors. Data Type Compatibility table does not include strings. Is there a way of passing strings?
Jul 30 2013
On Tuesday, 30 July 2013 at 20:17:34 UTC, John Colvin wrote:On Tuesday, 30 July 2013 at 20:09:01 UTC, Milvakili wrote:Thanks. Is there any work in progress related to string passing? I think string passing should be solved automatically. Coz otherwise one need to write wrapper for each c++ function that has a string parameter. thanks.On Tuesday, 30 July 2013 at 20:02:51 UTC, Dicebot wrote:Correct. Just thinking off the top of my head: you could probably hack something together though with a struct and casting.On Tuesday, 30 July 2013 at 19:52:44 UTC, Milvakili wrote:So I need to pass them as char*, I can not pass them as string?I'm linking D with C++ lib.a file. When the C++ function has compatible data types I can call them from D. But when I changed the parameter to string I got bunch of errors. Data Type Compatibility table does not include strings. Is there a way of passing strings?
Jul 30 2013
On Tuesday, 30 July 2013 at 20:22:46 UTC, Milvakili wrote:Thanks. Is there any work in progress related to string passing? I think string passing should be solved automatically. Coz otherwise one need to write wrapper for each c++ function that has a string parameter. thanks.c_function(toStringz("hello").ptr) does not seem that bad, what is the issue here?
Jul 30 2013
On Tuesday, 30 July 2013 at 20:53:55 UTC, Dicebot wrote:On Tuesday, 30 July 2013 at 20:22:46 UTC, Milvakili wrote:I want to point out that one of the dangers (as I've heard it, I haven't actually run into this), is that since the garbage collector won't scan your C function's internals, the caller *must* keep a reference in his code to preserve the allocated array. The above scheme does not do that: If the garbage collector runs after the start of the call, but before the end of the function, then you are in trouble. I'd do it like this: //---- string lifeline = toStringz("hello"); //Preserve reference c_function(lifeline.ptr); //Make call lifeline = null; //Release reference //---- That's assuming c_function won't preserve the string somewhere. If it does, things get more complicated.Thanks. Is there any work in progress related to string passing? I think string passing should be solved automatically. Coz otherwise one need to write wrapper for each c++ function that has a string parameter. thanks.c_function(toStringz("hello").ptr) does not seem that bad, what is the issue here?
Jul 31 2013
On Wednesday, 31 July 2013 at 07:54:00 UTC, monarch_dodra wrote:I want to point out that one of the dangers (as I've heard it, I haven't actually run into this), is that since the garbage collector won't scan your C function's internals, the caller *must* keep a reference in his code to preserve the allocated array. The above scheme does not do that: If the garbage collector runs after the start of the call, but before the end of the function, then you are in trouble.You have to work very hard to not find it either in the stack or in a register during the function call. So as long as the C code do not keep a reference, ou should be fine.I'd do it like this: //---- string lifeline = toStringz("hello"); //Preserve reference c_function(lifeline.ptr); //Make call lifeline = null; //Release reference //----This is plain useless. dead store elimination will remove the "release reference", the variable lifeline promoted to register (its ptr part anyway, it length part is likely to be trashed right away by the function call). On X86, the string will be returned in EAX and EDX (ptr in EDX if I'm not mistaken). So the length will be erased by copying EDX to EAX (now both contains the ptr, length is lost) and the call made right away (first argument is passed in EAX).That's assuming c_function won't preserve the string somewhere. If it does, things get more complicated.If it does, that means big trouble, even in pure C, as it is now unclear who is the owner of the string. A recipe for memory corruption/leak.
Jul 31 2013
On Wednesday, 31 July 2013 at 08:20:48 UTC, deadalnix wrote:On Wednesday, 31 July 2013 at 07:54:00 UTC, monarch_dodra wrote:I'll take your word for it then. As I said, I didn't run into this before, but I had read some other posts that mentioned this problem. I might have it confused with dynamic libs though? I don't know. Forget I said anything then.I want to point out that one of the dangers (as I've heard it, I haven't actually run into this), is that since the garbage collector won't scan your C function's internals, the caller *must* keep a reference in his code to preserve the allocated array. The above scheme does not do that: If the garbage collector runs after the start of the call, but before the end of the function, then you are in trouble.You have to work very hard to not find it either in the stack or in a register during the function call. So as long as the C code do not keep a reference, ou should be fine.I'd do it like this: //---- string lifeline = toStringz("hello"); //Preserve reference c_function(lifeline.ptr); //Make call lifeline = null; //Release reference //----This is plain useless. dead store elimination will remove the "release reference", the variable lifeline promoted to register (its ptr part anyway, it length part is likely to be trashed right away by the function call). On X86, the string will be returned in EAX and EDX (ptr in EDX if I'm not mistaken). So the length will be erased by copying EDX to EAX (now both contains the ptr, length is lost) and the call made right away (first argument is passed in EAX).Most probably.That's assuming c_function won't preserve the string somewhere. If it does, things get more complicated.If it does, that means big trouble, even in pure C, as it is now unclear who is the owner of the string. A recipe for memory corruption/leak.
Jul 31 2013
On Tuesday, 30 July 2013 at 20:22:46 UTC, Milvakili wrote:On Tuesday, 30 July 2013 at 20:17:34 UTC, John Colvin wrote:I had a crack at making this work, but I'm stuck on some basics and I don't know a great deal about c++ really //inter.cpp #include<string> #include<iostream> using namespace std; void printString(string* s) { cout << s << "\n"; } string *strD2Cpp(char *ptr, unsigned long long length) { return new std::string(ptr, length); } //inter.d extern(C++) { interface CppString{} CppString strD2Cpp(char* ptr, size_t length); void printString(CppString s); } void main() { string s = "2432qreafdsa"; auto s_cpp = strD2Cpp(s.dup.ptr, s.length); printString(s_cpp); } $ dmd -c -m64 inter.d $ g++ -c -m64 inter.cpp -ointercpp.o $ g++ inter.o intercpp.o -ointer -lphobos2 inter.o: In function `_Dmain': inter.d:(.text._Dmain+0x48): undefined reference to `printString(CppString*)' collect2: error: ld returned 1 exit status Is this an incompatibility between dmd and g++? I'm on linux x64 How come it's happy to have CppString as the return type of strD2Cpp but not as a parameter to printString? Also, using size_t in inter.cpp caused linker errors, hence the unsigned long long.On Tuesday, 30 July 2013 at 20:09:01 UTC, Milvakili wrote:Thanks. Is there any work in progress related to string passing? I think string passing should be solved automatically. Coz otherwise one need to write wrapper for each c++ function that has a string parameter. thanks.On Tuesday, 30 July 2013 at 20:02:51 UTC, Dicebot wrote:Correct. Just thinking off the top of my head: you could probably hack something together though with a struct and casting.On Tuesday, 30 July 2013 at 19:52:44 UTC, Milvakili wrote:So I need to pass them as char*, I can not pass them as string?I'm linking D with C++ lib.a file. When the C++ function has compatible data types I can call them from D. But when I changed the parameter to string I got bunch of errors. Data Type Compatibility table does not include strings. Is there a way of passing strings?
Jul 30 2013
On 7/30/2013 3:01 PM, John Colvin wrote:$ dmd -c -m64 inter.d $ g++ -c -m64 inter.cpp -ointercpp.o $ g++ inter.o intercpp.o -ointer -lphobos2 inter.o: In function `_Dmain': inter.d:(.text._Dmain+0x48): undefined reference to `printString(CppString*)' collect2: error: ld returned 1 exit statusYou might want to look at the name mangling of the D printString vs the name mangling of the C++ one.
Jul 30 2013
On Wednesday, 31 July 2013 at 02:53:47 UTC, Walter Bright wrote:On 7/30/2013 3:01 PM, John Colvin wrote:Woops, yeah that was never going to work. However, I did come across something interesting: gcc mangles std::string as "Ss", see here: https://github.com/mirrors/gcc/blob/master/gcc/cp/mangle.c#L472 It also doesn't bother mangling the length for these special case identifiers, e.g. void printString(string * s, BLAHBLAH fdsa) becomes _Z11printStringPSs8BLAHBLAH Any ideas how we can get around this? Some std c++ type instrinsics in dmd?$ dmd -c -m64 inter.d $ g++ -c -m64 inter.cpp -ointercpp.o $ g++ inter.o intercpp.o -ointer -lphobos2 inter.o: In function `_Dmain': inter.d:(.text._Dmain+0x48): undefined reference to `printString(CppString*)' collect2: error: ld returned 1 exit statusYou might want to look at the name mangling of the D printString vs the name mangling of the C++ one.
Jul 31 2013
On Wednesday, 31 July 2013 at 13:15:58 UTC, John Colvin wrote:Any ideas how we can get around this? Some std c++ type instrinsics in dmd?Maybe http://d.puremagic.com/issues/show_bug.cgi?id=10077 can help?
Jul 31 2013
On Wednesday, 31 July 2013 at 13:39:29 UTC, Dicebot wrote:On Wednesday, 31 July 2013 at 13:15:58 UTC, John Colvin wrote:Yikes that's quite a rabbit hole, it's all a bit beyond me tbh.Any ideas how we can get around this? Some std c++ type instrinsics in dmd?Maybe http://d.puremagic.com/issues/show_bug.cgi?id=10077 can help?
Jul 31 2013
On Tuesday, 30 July 2013 at 20:09:01 UTC, Milvakili wrote:So I need to pass them as char*, I can not pass them as string?I would pass it as a char* and a size_t for length. extern(C++) void cpp_func(char* strptr, size_t strlen); void main() { string foo = "test"; cpp_func(foo.ptr, foo.length); } It'd be important on the C++ side to remember that it is NOT zero terminated, and always use that length parameter instead of normal C functions. But that'd give the most efficiency, since that's using the same representation as D itself.
Jul 30 2013
On Tuesday, 30 July 2013 at 20:09:01 UTC, Milvakili wrote:So I need to pass them as char*, I can not pass them as string?C++ doesn't have an immutable(char)[], it has char* and its own string class. To communicate with it one must choose a type both languages can understand, char* is that. D may be able to get away with providing a C++ string, but I'm not familiar with the integration layer.
Jul 30 2013
On Tuesday, 30 July 2013 at 20:57:55 UTC, Jesse Phillips wrote:On Tuesday, 30 July 2013 at 20:09:01 UTC, Milvakili wrote:const char*, char const* are equivalent to const(char)* in D.So I need to pass them as char*, I can not pass them as string?C++ doesn't have an immutable(char)[], it has char* and its own string class. To communicate with it one must choose a type both languages can understand, char* is that. D may be able to get away with providing a C++ string, but I'm not familiar with the integration layer.
Jul 30 2013
On Wednesday, 31 July 2013 at 05:44:38 UTC, deadalnix wrote:On Tuesday, 30 July 2013 at 20:57:55 UTC, Jesse Phillips wrote:I was referring to string types: http://www.cplusplus.com/reference/string/string/ If his C++ functions takes a const char* he should be passing it a const/immutable(char)* as you say, not an immutable(char)[]On Tuesday, 30 July 2013 at 20:09:01 UTC, Milvakili wrote:const char*, char const* are equivalent to const(char)* in D.So I need to pass them as char*, I can not pass them as string?C++ doesn't have an immutable(char)[], it has char* and its own string class. To communicate with it one must choose a type both languages can understand, char* is that. D may be able to get away with providing a C++ string, but I'm not familiar with the integration layer.
Jul 30 2013
On Wednesday, 31 July 2013 at 06:07:07 UTC, Jesse Phillips wrote:On Wednesday, 31 July 2013 at 05:44:38 UTC, deadalnix wrote:In C++, std::string own its own copy of the string. So it is safe to pass a D const char* to the constructor.On Tuesday, 30 July 2013 at 20:57:55 UTC, Jesse Phillips wrote:I was referring to string types: http://www.cplusplus.com/reference/string/string/ If his C++ functions takes a const char* he should be passing it a const/immutable(char)* as you say, not an immutable(char)[]On Tuesday, 30 July 2013 at 20:09:01 UTC, Milvakili wrote:const char*, char const* are equivalent to const(char)* in D.So I need to pass them as char*, I can not pass them as string?C++ doesn't have an immutable(char)[], it has char* and its own string class. To communicate with it one must choose a type both languages can understand, char* is that. D may be able to get away with providing a C++ string, but I'm not familiar with the integration layer.
Jul 31 2013
On Wednesday, 31 July 2013 at 07:17:15 UTC, deadalnix wrote:In C++, std::string own its own copy of the string. So it is safe to pass a D const char* to the constructor.I thought the discussion was about: void someFun(std::string arg) { ...} Pass D string to someFun. I do not believe const(char) * is valid.
Jul 31 2013
On Tuesday, 30 July 2013 at 20:09:01 UTC, Milvakili wrote:On Tuesday, 30 July 2013 at 20:02:51 UTC, Dicebot wrote:You can't pass them as string because they have different representations. A C++ string is null terminated while a D string is not. If you pass a D string to C++ then it will not have the same length and give undesirable behavior. If you really want to use strings, then wrap each C++ function with one that converts the string to a C string. If D used both pascal and C++ style strings as one(a waste of 1 extra byte per string) then life would be easier.On Tuesday, 30 July 2013 at 19:52:44 UTC, Milvakili wrote:So I need to pass them as char*, I can not pass them as string?I'm linking D with C++ lib.a file. When the C++ function has compatible data types I can call them from D. But when I changed the parameter to string I got bunch of errors. Data Type Compatibility table does not include strings. Is there a way of passing strings?
Jul 30 2013
I'm using toStringz() and it works fine if you're c++ function parms are const ref or by value: void funk(const std::string& val) {} void funk(std::string val) {}
Jul 30 2013
(damn, no edit!) I'm using toStringz() and it works fine if you're c++ function parms are const ref or by value: void funk(const std::string& val) {} void funk(std::string val) {} then use a very simple D script to auto-generated C wrapper functions from headers. All the script does is: void funkD(const char* c) {funk(c);} It wouldn't work for functions taking a string by ref or pointer, that would require too much effort in the generating script for my liking. You may baulk at the idea of writing a script for auto-generating the code but really it is very simple.
Jul 30 2013
On 07/30/2013 02:17 PM, JS wrote:A C++ string is null terminated while a D string is not.I think the OP means std::string, which also is not zero-terminated. (On the other hand, C strings are zero-terminated.)If you pass a D string to C++ then it will not have the same lengthand giveundesirable behavior.That's an important consideration. char is not UTF-8 code unit in C and C++. Ali
Jul 30 2013
On Wednesday, 31 July 2013 at 05:56:13 UTC, Ali Çehreli wrote:On 07/30/2013 02:17 PM, JS wrote:You can obtain a 0 terminated "const char*" from an std::string in 0(1) using c_str. While the C++98 standard doesn't mandate it, the above requirement means that 99% of string implementations are using arraysinternally. The C++11 standard *does* mandate that the implementation use arrays internally. So that means you can get a valid char* from &myString[0]. That string will not be 0 terminated, but all the major compiler providers (AFAIK) make that guarantee as an extension.A C++ string is null terminated while a D string is not.I think the OP means std::string, which also is not zero-terminated. (On the other hand, C strings are zero-terminated.)
Jul 31 2013
On Tuesday, 30 July 2013 at 19:52:44 UTC, Milvakili wrote:I'm linking D with C++ lib.a file. When the C++ function has compatible data types I can call them from D. But when I changed the parameter to string I got bunch of errors. Data Type Compatibility table does not include strings. Is there a way of passing strings?When it come to C++, passing via C string is always an option, but kind of a waste as you'll allocate a temporary string and go through it twice. My solution of choice it to create a function in C++ that take a const char* and a size_t length as parameter (and other C++ parameters of the function and forward to C++ . Doing so, you only allocate the C++ string as C++ mandate and don't need to go through it. But you need a wrapper.
Jul 30 2013