Thread overview
C API / const char *text / std.string.toStringz pointer is always NULL on C side
May 16, 2018
Robert M. Münch
May 16, 2018
rikki cattermole
May 16, 2018
Robert M. Münch
May 18, 2018
Robert M. Münch
May 18, 2018
Adam D. Ruppe
May 19, 2018
Robert M. Münch
May 19, 2018
kinke
May 16, 2018
I have an extern(C) function in a DLL with this signature:

result* myfunc(double x, double y, const char *text, stuff *myStuff, bool flag);

I call it like this:

result = myfunc(0, 0, std.string.toStringz("1"), stuff, true);


The problem is, that on the DLL side *text is always NULL. I doesn't matter what I put as third argument. And even more strange, I have an other function with a const char* as first argument. There everything is working...

Any idea what cause this could be? This is really strange...


-- 
Robert M. Münch
http://www.saphirion.com
smarter | better | faster

May 17, 2018
On 17/05/2018 3:07 AM, Robert M. Münch wrote:
> I have an extern(C) function in a DLL with this signature:
> 
> result* myfunc(double x, double y, const char *text, stuff *myStuff, bool flag);
> 
> I call it like this:
> 
> result = myfunc(0, 0, std.string.toStringz("1"), stuff, true);
> 
> 
> The problem is, that on the DLL side *text is always NULL. I doesn't matter what I put as third argument. And even more strange, I have an other function with a const char* as first argument. There everything is working...
> 
> Any idea what cause this could be? This is really strange...

Please post the C function prototype.

May 16, 2018
On 5/16/18 11:07 AM, Robert M. Münch wrote:
> I have an extern(C) function in a DLL with this signature:
> 
> result* myfunc(double x, double y, const char *text, stuff *myStuff, bool flag);
> 
> I call it like this:
> 
> result = myfunc(0, 0, std.string.toStringz("1"), stuff, true);

toStringz isn't necessary, string literals always are null terminated, and implicitly cast to const char *.

> The problem is, that on the DLL side *text is always NULL. I doesn't matter what I put as third argument. And even more strange, I have an other function with a const char* as first argument. There everything is working...
> 
> Any idea what cause this could be? This is really strange...

It sounds very much like a mismatch of parameters on the prototype. Anything extern(C) has no mangling, and so you can specify the wrong parameters and it still compiles.

Double check the parameter types, and if possible, reduce to a simple compilable example that can be tested by others.

-Steve

May 16, 2018
On 2018-05-16 15:09:41 +0000, rikki cattermole said:

> On 17/05/2018 3:07 AM, Robert M. Münch wrote:
>> I have an extern(C) function in a DLL with this signature:
>> 
>> result* myfunc(double x, double y, const char *text, stuff *myStuff, bool flag);
>> 
>> I call it like this:
>> 
>> result = myfunc(0, 0, std.string.toStringz("1"), stuff, true);
>> 
>> 
>> The problem is, that on the DLL side *text is always NULL. I doesn't matter what I put as third argument. And even more strange, I have an other function with a const char* as first argument. There everything is working...
>> 
>> Any idea what cause this could be? This is really strange...
> 
> Please post the C function prototype.

Well, for C see above on the D side:

	extern(C) {
  		result myfunc(double x, double y, const char *text, stuff *myStuff, bool measureOnly);
	}

result is a:

   extern (C++, class) struct result {
     double w;
     double h;
   }



-- 
Robert M. Münch
http://www.saphirion.com
smarter | better | faster

May 16, 2018
On 5/16/18 12:53 PM, Robert M. Münch wrote:
> On 2018-05-16 15:09:41 +0000, rikki cattermole said:
> 
>> On 17/05/2018 3:07 AM, Robert M. Münch wrote:
>>> I have an extern(C) function in a DLL with this signature:
>>>
>>> result* myfunc(double x, double y, const char *text, stuff *myStuff, bool flag);
>>>
>>> I call it like this:
>>>
>>> result = myfunc(0, 0, std.string.toStringz("1"), stuff, true);
>>>
>>>
>>> The problem is, that on the DLL side *text is always NULL. I doesn't matter what I put as third argument. And even more strange, I have an other function with a const char* as first argument. There everything is working...
>>>
>>> Any idea what cause this could be? This is really strange...
>>
>> Please post the C function prototype.
> 
> Well, for C see above on the D side:
> 
>      extern(C) {
>            result myfunc(double x, double y, const char *text, stuff *myStuff, bool measureOnly);
>      }

Shouldn't the result be a pointer?

-Steve
May 18, 2018
On 2018-05-16 17:46:59 +0000, Steven Schveighoffer said:

>> Well, for C see above on the D side:
>> 
>>     extern(C) {
>>           result myfunc(double x, double y, const char *text, stuff
>> *myStuff, bool measureOnly);
>>     }
> 
> Shouldn't the result be a pointer?

Indeed. And you know what? That was causing the problem.

So, having a wrong return-type here, resulted in the const char *text parameter always being NULL. Not sure I understand the relation but looks strange to me... at least not very obvious.

-- 
Robert M. Münch
http://www.saphirion.com
smarter | better | faster

May 18, 2018
On Friday, 18 May 2018 at 14:06:11 UTC, Robert M. Münch wrote:
> So, having a wrong return-type here, resulted in the const char *text parameter always being NULL. Not sure I understand the relation but looks strange to me... at least not very obvious.

A value struct return is actually done via a hidden pointer parameter (so the function can construct it in-place for the caller, a standard optimization), so it just shifted all the other arguments to the side, causing one of those 0's to be interpreted as the string.
May 19, 2018
On 2018-05-18 14:42:17 +0000, Adam D. Ruppe said:

> On Friday, 18 May 2018 at 14:06:11 UTC, Robert M. Münch wrote:
>> So, having a wrong return-type here, resulted in the const char *text parameter always being NULL. Not sure I understand the relation but looks strange to me... at least not very obvious.
> 
> A value struct return is actually done via a hidden pointer parameter (so the function can construct it in-place for the caller, a standard optimization), so it just shifted all the other arguments to the side, causing one of those 0's to be interpreted as the string.

Wow, thanks for the clear explanation. Without very deep internal knowhow I don't think anyone is able to ever guess this.

Is this somehwere documented?

-- 
Robert M. Münch
http://www.saphirion.com
smarter | better | faster

May 19, 2018
On Saturday, 19 May 2018 at 17:33:08 UTC, Robert M. Münch wrote:
> On 2018-05-18 14:42:17 +0000, Adam D. Ruppe said:
>> A value struct return is actually done via a hidden pointer parameter (so the function can construct it in-place for the caller, a standard optimization), so it just shifted all the other arguments to the side, causing one of those 0's to be interpreted as the string.
>
> [...]
>
> Is this somehwere documented?

https://docs.microsoft.com/en-us/cpp/build/return-values-cpp:

> Otherwise, the caller assumes the responsibility of allocating
> memory and passing a pointer for the return value as the first
> argument. Subsequent arguments are then shifted one argument
> to the right.