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.
Go unsafe pointers mean the types whose underlying types are unsafe. Pointer . The zero values of unsafe pointers are also represented with the predeclared identifier nil . Before Go 1.17, the unsafe standard package has already provided three functions.
The * and & operators In Go a pointer is represented using the * (asterisk) character followed by the type of the stored value. In the zero function xPtr is a pointer to an int . * is also used to “dereference” pointer variables. Dereferencing a pointer gives us access to the value the pointer points to.
uintptr is generally used to perform indirect arithmetic operations on unsafe pointers for unsafe memory access. First, unsafe. Pointer is converted to uintptr , and then the arithmetic operation is performed on uintptr . Finally, it is converted back to unsafe.
Using pointers in Go If we want to make the first code snippet work, we can make use of pointers. In Go, every function argument is passed by value, meaning that the value is copied and passed, and by changing the argument value in the function body, nothing changes with the underlying variable.
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)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With