Thread overview
how to pass a ubyte[] to c interface?
Mar 13, 2015
zhmt
Mar 13, 2015
zhmt
Mar 13, 2015
Rikki Cattermole
Mar 13, 2015
zhmt
Mar 13, 2015
Rikki Cattermole
Mar 13, 2015
Ali Çehreli
Mar 13, 2015
zhmt
March 13, 2015
ubyte[] arr ;

I pass the arr.ptr to c program, it fails silently.

Is there any way to cast a ubyte[] to a clang pointer?
March 13, 2015
I have some source code of vibe.d, it does this in the same way, and it works .

void read(ubyte[] dst)
	{
		checkConnected(false);
		acquireReader();
		scope(exit) releaseReader();
		while (dst.length > 0) {
			checkConnected(false);
			logTrace("evbuffer_read %d bytes (fd %d)", dst.length, m_ctx.socketfd);
			auto nbytes = bufferevent_read(m_ctx.event, dst.ptr, dst.length);
			logTrace(" .. got %d bytes", nbytes);
			dst = dst[nbytes .. $];

			if( dst.length == 0 ) break;

			checkConnected(false);
			m_ctx.core.yieldForEvent();
		}
		logTrace("read data");
	}
March 13, 2015
On 13/03/2015 7:35 p.m., zhmt wrote:
> ubyte[] arr ;
>
> I pass the arr.ptr to c program, it fails silently.
>
> Is there any way to cast a ubyte[] to a clang pointer?

Theoretically this should work.

D:

void func(ubyte[] value) {
	func(value.length, value.ptr);
}

extern(C) void func(size_t length, ubyte*);

C:
void func(size_t length, ubyte*) {
	// ...
}
March 13, 2015
On Friday, 13 March 2015 at 06:39:31 UTC, Rikki Cattermole wrote:
> On 13/03/2015 7:35 p.m., zhmt wrote:
>> ubyte[] arr ;
>>
>> I pass the arr.ptr to c program, it fails silently.
>>
>> Is there any way to cast a ubyte[] to a clang pointer?
>
> Theoretically this should work.
>
> D:
>
> void func(ubyte[] value) {
> 	func(value.length, value.ptr);
> }
>
> extern(C) void func(size_t length, ubyte*);
>
> C:
> void func(size_t length, ubyte*) {
> 	// ...
> }

Thank you for your confirm,I will try again.
March 13, 2015
On 13/03/2015 7:47 p.m., zhmt wrote:
> On Friday, 13 March 2015 at 06:39:31 UTC, Rikki Cattermole wrote:
>> On 13/03/2015 7:35 p.m., zhmt wrote:
>>> ubyte[] arr ;
>>>
>>> I pass the arr.ptr to c program, it fails silently.
>>>
>>> Is there any way to cast a ubyte[] to a clang pointer?
>>
>> Theoretically this should work.
>>
>> D:
>>
>> void func(ubyte[] value) {
>>     func(value.length, value.ptr);
>> }
>>
>> extern(C) void func(size_t length, ubyte*);
>>
>> C:
>> void func(size_t length, ubyte*) {
>>     // ...
>> }
>
> Thank you for your confirm,I will try again.

Just be careful about GC pointers. They could be free'd and the c library thinks it is still live.
Either keep a copy of the pointer alive on the heap somewhere or tell the GC to ignore it.
March 13, 2015
On 03/12/2015 11:35 PM, zhmt wrote:

> ubyte[] arr ;
>
> I pass the arr.ptr to c program

Unless there is sentinel value at the end of the array, you must also pass the number of elements (as Rikki Cattermole has shown).

However, if the C function holds on to that pointer for later use, you must also keep the array alive. You can ensure that by two general ways:

a) The D-side slice must not be a local slice. For example, it can be a member of a long-living object or it is a module-scope variable.

b) Tell the garbage collector that there is indeed a reference to that memory block somewhere else (even though there is no D-side reference to it). You can do this with GC.addRoot. (The opposite function is GC.removeRoot.)

>, it fails silently.

That's not good.

> Is there any way to cast a ubyte[] to a clang pointer?

Going off-topic, I think you mean the C language when you say "clang", which may be confusing because there is also the compiler called clang. :)

Ali

March 13, 2015
On Friday, 13 March 2015 at 06:56:33 UTC, Ali Çehreli wrote:
> On 03/12/2015 11:35 PM, zhmt wrote:
>
> > ubyte[] arr ;
> >
> > I pass the arr.ptr to c program
>
> Unless there is sentinel value at the end of the array, you must also pass the number of elements (as Rikki Cattermole has shown).
>
> However, if the C function holds on to that pointer for later use, you must also keep the array alive. You can ensure that by two general ways:
>
> a) The D-side slice must not be a local slice. For example, it can be a member of a long-living object or it is a module-scope variable.
>
> b) Tell the garbage collector that there is indeed a reference to that memory block somewhere else (even though there is no D-side reference to it). You can do this with GC.addRoot. (The opposite function is GC.removeRoot.)
>
> >, it fails silently.
>
> That's not good.
>
> > Is there any way to cast a ubyte[] to a clang pointer?
>
> Going off-topic, I think you mean the C language when you say "clang", which may be confusing because there is also the compiler called clang. :)
>
> Ali


sorry for "clang", I mean c , not clang of mac.

Thanks for you advice, I use coroutine, so the array will hold in stack, will not be gc before return.

And I successfully passed the arr.ptr to c program. I found the root of problem:
The order of method declaration in c++ class and d interface must be exactly the same:

this is d code:

        interface CConn
	 {
		void free();
		int connect(ubyte* ip,int port,CFiberCtx fiberctx);
		int read(ubyte* buf,int offset, int len,CFiberCtx fiberctx);
		int readSome(ubyte* buf,int offset, int len,CFiberCtx fiberctx);
		int write(ubyte* buf,int offset, int len,CFiberCtx fiberctx);
	}

this is c++ class:

class CConn
{
public:
  //==== dlang interfaces;
  virtual void free();
  virtual int connect(char* ip,int port,CFiberCtx *fiberctx);
  virtual int read(char* buf,int offset, int len,CFiberCtx *fiberctx);
  virtual int write(char* buf,int offset, int len,CFiberCtx *fiberctx); //ERROR : swap this line with below, everything will be ok
  virtual int readSome(char* buf,int offset, int len,CFiberCtx *fiberctx);
}

After swapping the last two lines, everything goes well.

The tutorial of d dont mention this.

Thanks for all replies.