Convert **T to *unsafe.Pointer in Go
-
26-06-2021 - |
문제
How do I convert a variable of type **T
to *unsafe.Pointer
?
The example below will give the compilation error:
cannot convert &ptr (type **s) to type *unsafe.Pointer
package main
import (
"sync/atomic"
"unsafe"
)
type s struct {
value int
}
func main(){
var ptr *s
a := &s{42}
old := ptr
atomic.CompareAndSwapPointer(
(*unsafe.Pointer)(&ptr), // &unsafe.Pointer(ptr)
unsafe.Pointer(old),
unsafe.Pointer(a))
}
If I switch (*unsafe.Pointer)(&ptr)
to &unsafe.Pointer(ptr)
, I will get this compilation error:
cannot take the address of unsafe.Pointer(ptr)
Ps. I choose to make an example with sync/atomic
because that is one situation where you actually have to do such a conversion.
Edit
One incorrect solution would be to use a temporary variable:
up := unsafe.Pointer(ptr)
atomic.CompareAndSwapPointer(&up, ...
While it compiles, the CAS will only swap what is stored in up
and not in ptr
. This is not the desired result, as zeebo@#go-nuts pointed out.
해결책
mcef@#go-nuts posted the answer how to convert **T:
(*unsafe.Pointer)(unsafe.Pointer(ptr)), where ptr is of type **T.
zeebo@#go-nuts provided a working example (posted here with permission):
package main
import (
"fmt"
"sync/atomic"
"unsafe"
)
type T struct {
value int
}
func Swap(dest **T, old, new *T) bool {
udest := (*unsafe.Pointer)(unsafe.Pointer(dest))
return atomic.CompareAndSwapPointer(udest,
unsafe.Pointer(old),
unsafe.Pointer(new),
)
}
func main() {
x := &T{42}
n := &T{50}
fmt.Println(*x, *n)
p := x
Swap(&x, p, n)
fmt.Println(*x, *n)
}