Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert **T to *unsafe.Pointer in Go

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.

like image 737
ANisus Avatar asked Aug 14 '12 21:08

ANisus


People also ask

What is unsafe pointer in Go?

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.

How do I dereference a pointer in Golang?

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.

What is Uintptr Go?

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.

Can you use pointers in Go?

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.


1 Answers

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)
}
like image 93
ANisus Avatar answered Sep 24 '22 11:09

ANisus