This is a creation in Article, where the information may have evolved or changed.
"Go language Combat" reading notes, not to be continued, welcome to sweep code attention flysnow_org
to the public or website http://www.flysnow.org/, the first time to see follow-up notes. If you feel helpful, share it with your friends and thank you for your support.
The go language is designed to be a strong type of static language for ease of writing, high efficiency, and reduced complexity. A strong type means that once defined, its type cannot be changed, and static means that the type check is done before it is run.
For security reasons, the Go language allows two pointer types to be converted.
Pointer type conversions
We typically use a pointer *T
type that represents a pointer to a type T variable. For security reasons, two different pointer types cannot be converted to one another, for example *int
*float64
.
12345678 |
func Main ()ip:=&ivar fp *float64 = (*float64) (IP) fmt. PRINTLN (FP)} |
The above code when we compile, will be prompted cannot convert ip (type *int) to type *float64
, that is, can not be forced to transform. So what if we still need to do the conversion? This requires us to use the unsafe package Pointer
, let's see unsafe.Pointer
what it is, and then how to convert it.
Pointer
unsafe.Pointer
is a special kind of pointer, it can contain any type of address, a bit similar to the C language of the void* pointer, all-round.
12345678910 |
func Main ()ip:=&ivar fp *float64 = (*float643fmt. Println (i)} |
In the example above, we can convert to *int
*float64
, and we try to operate on the new *float64
, the print output i
, the same address will be found to i
be changed.
The above example does not have any practical meaning, but we show that with unsafe.Pointer
this universal pointer, we can *T
do any conversion between them.
123 |
type int type Pointer *arbitrarytype |
Can see unsafe.Pointer
is actually a *int
, a general-purpose pointer.
Let's take a look at unsafe.Pointer
the 4 rules.
- Any pointer can be converted to
unsafe.Pointer
unsafe.Pointer
can be converted to any pointer
uintptr
can be converted tounsafe.Pointer
unsafe.Pointer
can be converted touintptr
The first two rules we have just demonstrated, mainly for *T1
and *T2
between the conversion, then the last two rules is what to do? We all know that we can't calculate the offsets, and we can't calculate them, but we can switch the pointers to the cheap ones, so *T
uintptr
uintptr
We can access the specific memory and read and write to different memory.
Let's demonstrate the use of a field in the struct structure by modifying the pointer offset uintptr
.
1234567891011121314151617 |
func Main () {u:=new(user) fmt. Println (*u) pname:= (*string) (unsafe. Pointer (U)) *pname="Zhang San"page:= (*int) (unsafe. Pointer (uintptrfmt. Println (*u)}typestructstringint} |
Above, we use the memory offset to navigate to the fields we need to manipulate, and then change their values.
The first user
time the name
value is modified, because name
it is the first field, so there is no offset, we get user
the pointer, and then by moving unsafe.Pointer
*string
to the assignment operation.
The second modified user
age
value, because age
it is not the first field, so we need a memory offset, the memory offset involves the calculation can only pass uintptr
, we have to put user
the pointer address to the first uintptr
, and then we pass unsafe.Offsetof(u.age)
Gets the value that needs to be offset, and the address operation (+) offset.
Now after the offset, the address is already user
the age
field, if you want to assign it, we need to turn to uintptr
*int
be able. So we can do it by turning uintptr
unsafe.Pointer
it into a switch *int
.
Here we can see that the second offset of our expression is very long, but also do not fragment them, not as follows.
123 |
temp:=uintptr(unsafe. Pointer (U)) +unsafe. Offsetof (u.age) page:= (*int |
Logically, the above code will not have any problem, but this will involve the GC, if we have these temporary variables are GC, then the resulting memory operation is wrong, we finally operate, do not know which block of memory, will cause inexplicable problems.
Summary
Unsafe is unsafe, so we should use it as sparingly as possible, such as the manipulation of memory, which bypasses the security of the go itself, and improper operation, which can destroy a piece of memory, and this problem is very difficult to locate.
Of course we can use it, such as conversions between arrays of the same underlying type, such as when using some of the functions in the Sync/atomic package, or when accessing a private field of a struct;
Also, the entire unsafe package is for the go compiler, not run, when we compile, the go compiler has processed them all.
"Go language Combat" reading notes, not to be continued, welcome to sweep code attention flysnow_org
to the public or website http://www.flysnow.org/, the first time to see follow-up notes. If you feel helpful, share it with your friends and thank you for your support.