www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - cast ref pointer

reply =?UTF-8?B?THXDrXM=?= Marques <luis luismarques.eu> writes:
This works, obviously (i.e. it prints 42):

     void foo(ref int* a)
     {
         static int j = 42;
         a = &j;
     }

     void bar(int* ptr)
     {
         foo(ptr);
         writeln(*ptr);
     }

     void main()
     {
         int i = 7;
         bar(&i);
     }

Unfortunately, if bar for some reason receives a void* pointer 
(e.g. C callback) this doesn't work:

     void bar(void* ptr)
     {
         foo(cast(int*) ptr); // error
         writeln(*cast(int*) *ptr);
     }

I think the underlying idea is sound (use ptr as an lvalue, but 
with int* type), but since you can't cast(ref int*), I don't know 
how to express it in D code.
Jan 18
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 18 January 2018 at 15:25:38 UTC, Luís Marques wrote:
 I think the underlying idea is sound (use ptr as an lvalue, but 
 with int* type), but since you can't cast(ref int*), I don't 
 know how to express it in D code.
Simply define an intermediate. int* tmp = cast(int*) that_void_pointer; foo(tmp);
Jan 18
parent =?UTF-8?B?THXDrXM=?= Marques <luis luismarques.eu> writes:
On Thursday, 18 January 2018 at 16:08:32 UTC, Adam D. Ruppe wrote:
 Simply define an intermediate.

 int* tmp = cast(int*) that_void_pointer;
 foo(tmp);
In my actual case bar also receives its pointer by ref, so you would have to do something like: int* tmp = cast(int*) that_void_pointer; foo(tmp); that_void_pointer = tmp; This is a bit more noisy than what I would prefers (a more care is needed to check if this is properly optimized away), that's why I was looking for a more direct route, like a cast.
Jan 18
prev sibling next sibling parent reply ag0aep6g <anonymous example.com> writes:
On 01/18/2018 04:25 PM, Luís Marques wrote:
 This works, obviously (i.e. it prints 42):
 
      void foo(ref int* a)
      {
          static int j = 42;
          a = &j;
      }
 
      void bar(int* ptr)
      {
          foo(ptr);
          writeln(*ptr);
      }
 
      void main()
      {
          int i = 7;
          bar(&i);
      }
 
 Unfortunately, if bar for some reason receives a void* pointer (e.g. C 
 callback) this doesn't work:
 
      void bar(void* ptr)
      {
          foo(cast(int*) ptr); // error
You need a reinterpret-style cast here to get an lvalue: foo(* cast(int**) &ptr); The result has the same type (int*), but it refers to the very same memory location as `&ptr` does. So it's not just a temporary value, and it can be passed in a `ref` parameter.
          writeln(*cast(int*) *ptr);
You're dereferencing twice here. Do it only once, after casting: writeln(* cast(int*) ptr);
      }
Alernatively, you can make a local variable for the casted pointer and use that instead of the `ptr`: int* casted_ptr = cast(int*) ptr; foo(casted_ptr); writeln(*casted_ptr); That way, `ptr` itself won't be updated by `foo`, of course. But `ptr` isn't a `ref` parameter, so this only affects the insides of `bar` anyway.
Jan 18
parent =?UTF-8?B?THXDrXM=?= Marques <luis luismarques.eu> writes:
On Thursday, 18 January 2018 at 16:14:18 UTC, ag0aep6g wrote:
 On 01/18/2018 04:25 PM, Luís Marques wrote:
 You need a reinterpret-style cast here to get an lvalue:

     foo(* cast(int**) &ptr);
Right, that's what I wanted. Ugh, for some reason I was totally confused about this :-)
          writeln(*cast(int*) *ptr);
You're dereferencing twice here. Do it only once, after casting:
That was just a typo.
 That way, `ptr` itself won't be updated by `foo`, of course. 
 But `ptr` isn't a `ref` parameter, so this only affects the 
 insides of `bar` anyway.
Yeah, it was a bad example.
Jan 18
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 1/18/18 10:25 AM, Luís Marques wrote:
 This works, obviously (i.e. it prints 42):
 
      void foo(ref int* a)
      {
          static int j = 42;
          a = &j;
      }
 
      void bar(int* ptr)
      {
          foo(ptr);
          writeln(*ptr);
      }
Note, this, to me, seems odd. Of course this is not the full case, but you are not affecting anything except for the value of the local `ptr`. So I would be concerned this may not be what you want (if you are looking to affect something outside the callback). Other than that, the other responders are right, you just need to reinterpret the pointer. -Steve
Jan 18
parent reply =?UTF-8?B?THXDrXM=?= Marques <luis luismarques.eu> writes:
On Thursday, 18 January 2018 at 16:20:35 UTC, Steven 
Schveighoffer wrote:
 Note, this, to me, seems odd. Of course this is not the full 
 case, but you are not affecting anything except for the value 
 of the local `ptr`. So I would be concerned this may not be 
 what you want (if you are looking to affect something outside 
 the callback).
Yeah, I went overboard in reducing my scenario :( The actual function bar also receives by ref its pointer.
Jan 18
parent Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 18 January 2018 at 16:26:54 UTC, Luís Marques wrote:
 The actual function bar also receives by ref its pointer.
you might be better off receiving a pointer-to-pointer instead of ref. Then it will be encoded in the type and thus you can cast outer layers too and use intermediate more easily if you need. void foo(void** f) { bar(cast(int**) f); } int* a; foo(&a);
Jan 18