On 3/2/14 11:22 PM, Cosmin Apreutesei wrote: >> I may, of course, have misunderstood your question. Happens :/ > No pb, I'm usually too terse on the first try, it's a bad habit I have. > > So there are APIs (like malloc, cairo), where the objects are defined > as opaque structs, and the functions take a pointer to that, and then > there are APIs (like pthreads, fbclient, freetype), where the objects > are defined as pointers to opaque structs, and the functions take a > pointer to that (so the function takes a pointer to a pointer to an > opaque struct). The case I wanted to discuss was the later. > > In C, there's not much difference between the two styles, because you > can always take the address of everything with the `&` operator, > regardless of whether that thing is in the stack or heap or whatever. > If it's in RAM, it has an address and you can take it with `&`. > > AFAIK, in ffi, there's no addr() function, though I'm not sure why, > because print(ffi.new('double')) does show an address, and I'm pretty > sure that, at least for for structs and arrays, that address is > stable, which is necessary because you can take and hold pointers > pointing inside that struct/array. Yeah, tricky. > > So if I have ptr = ffi.cast('void *', some_address), I can't pass &ptr > to a function func(void**) because there's no ffi.addr(ptr). I can > pass ffi.new('void*[1]', ptr) though, but that allocates memory, at > least in some circumstances (someone please correct me if I'm wrong), > plus it's ugly :) As an alternative, I can say that ptr = > ffi.new(void*[1], some_address) and pass ptr around, but then I can't > apply metatype to void*[1]. Well, you can have a metatype, just not for void*[1]. Just assume that there's a struct hiding behind that void*[1]: local ffi = require('ffi') ffi.cdef"typedef struct foo_ foo_t;" ffi.metatype(ffi.typeof('foo_t'), { __index = { greet = function(self) print("Hey, ima:", self) end } }) local f = ffi.new('foo_t*[1]') local g = f[0] g:greet() > > Yet another alternative is to make a type for void* like this: > > typedef {void *p;} some_type; Yep, but that means you needs to pass `self.p` around when delegating to C functions from a method on your metatable. Which brings me back to my original point. You don't really need to box it. For the address of problem, I keep a foo_t*[1] lying around as an upvalue and just reuse that to save allocations: local foo_p_p = ffi.new('foo_t*[1]') function destroy(foo) foo_p_p[0] = foo ffi.C.destroy(foo_p_p) end Not terribly pretty, but it probably doesn't make sense to try to take the address of a cdata tagged value living somewhere on the Lua stack. -R