Go 言語にはポインタ演算がありません。 go 言語の構文はポインター算術をサポートしておらず、すべてのポインターは制御可能な範囲内で使用されますが、実際には、go 言語は unsafe パッケージの Pointer() メソッドを介してポインターを間接的に uintptr 型の数値に変換できます。ポインタ演算を実装します。
このチュートリアルの動作環境: Windows 7 システム、GO バージョン 1.18、Dell G3 コンピューター。
メモリは、シリアル番号を持つ一連の記憶ユニットです。変数は、コンパイラによってメモリ アドレスに割り当てられるニックネームです。では、ポインタとは何でしょうか?
ポインタは別のメモリ アドレス変数を指す値です。
ポインタは変数のメモリ アドレスを指し、ポインタは変数のメモリ アドレスに似ています。変数の値
コード スニペットを見てみましょう
func main() { a := 200 b := &a *b++ fmt.Println(a) }
#main 関数の最初の行で、新しい変数 a を定義し、値 200 を割り当てます。次に変数 b を定義し、変数 a のアドレスを b に代入します。 a の正確な格納アドレスはわかりませんが、変数 b に a のアドレスを格納することはできます。Go は強く型付けされた性質があるため、コードの 3 行目が最も厄介かもしれません。b には a が含まれています。変数のアドレスですが、変数に格納されている値をインクリメントしたいと考えています。
このように、b を逆参照し、代わりにポインタに続く b によって a を参照する必要があります。#最後の行には a の値が出力されます。a の値が 201 に増加していることがわかります次に、値に 1 を加算して、b に格納されているメモリ アドレスに格納し直します。
##Go 言語の関数パラメータはすべて値のコピーです。 変数を変更したい場合は、変数を指すアドレスを作成できます。ポインタ変数 。 C/C のポインタとは異なり、Go 言語のポインタはオフセットして操作することができず、安全なポインタです。
Go 言語のポインタを理解するには、ポインタ アドレス、ポインタ型、ポインタ値という 3 つの概念を理解する必要があります。
ポインタ アドレスとポインタ型
変数ポインタを取得するための構文は次のとおりです:ptr := &v // v的类型为Tその内:
v: 取得された変数を表します。 address, type is T
ptr: アドレスを受け取るために使用される変数 ptr の型は *T であり、T のポインタ型と呼ばれます。 *はポインタを表します。
func main() { a := 10 b := &a fmt.Printf("a:%d ptr:%p\n", a, &a) // a:10 ptr:0xc00001a078 fmt.Printf("b:%p type:%T\n", b, b) // b:0xc00001a078 type:*int fmt.Println(&b) // 0xc00000e018 }
ポインター演算子
func main() { x := 10 var p *int = &x //获取地址,保存到指针变量 *p += 20 //用指针间接引用,并更新对象 println(p, *p) //输出指针所存储的地址,以及目标对象 }
出力: 0xc000040780 30
func main() { x := 10 p := &x p++ //编译报错 invalid operation: p++ (non-numeric type *int) var p2 *int = p+1 //invalid operation: p + 1 (mismatched types *int and int) p2 = &x println(p == p2) //指向同一地址 }
unsafe.Pointer を使用してポインターを uintptr に変換し、加算および減算演算を実行できますが、不正なアクセスが発生する可能性があります。
ポインタ演算
- 但实际上,go 可以通过
unsafe.Pointer
来把指针转换为uintptr
类型的数字,来间接实现指针运算。- 这里请注意,
uintptr
是一种整数类型,而不是指针类型。
比如:
uintptr(unsafe.Pointer(&p)) + 1
就得到了 &p
的下一个字节的位置。然而,根据 《Go Programming Language》 的提示,我们最好直接把这个计算得到的内存地址转换为指针类型:
unsafe.Pointer(uintptr(unsafe.Pointer(&p) + 1))
因为 go 中是有垃圾回收机制的,如果某种 GC 挪动了目标值的内存地址,以整型来存储的指针数值,就成了无效的值。
同时也要注意,go 中对指针的 + 1,真的就只是指向了下一个字节,而 C 中 + 1
或者 ++
考虑了数据类型的长度,会自动指向当前值结尾后的下一个字节(或者说,有可能就是下一个值的开始)。如果 go 中要想实现同样的效果,可以使用 unsafe.Sizeof
方法:
unsafe.Pointer(uintptr(unsafe.Pointer(&p) + unsafe.Sizeof(p)))
最后,另外一种常用的指针操作是转换指针类型。这也可以利用 unsafe 包来实现:
var a int64 = 1 (*int8)(unsafe.Pointer(&a))
如果你没有遇到过需要转换指针类型的需求,可以看看这个项目(端口扫描工具),其中构建 IP 协议首部的代码,就用到了指针类型转换。
以上がGo言語でのポインタの操作は何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。