ホームページ  >  記事  >  バックエンド開発  >  Go言語でのポインタの操作は何ですか?

Go言語でのポインタの操作は何ですか?

青灯夜游
青灯夜游オリジナル
2023-01-04 10:30:293487ブラウズ

Go 言語にはポインタ演算がありません。 go 言語の構文はポインター算術をサポートしておらず、すべてのポインターは制御可能な範囲内で使用されますが、実際には、go 言語は unsafe パッケージの Pointer() メソッドを介してポインターを間接的に uintptr 型の数値に変換できます。ポインタ演算を実装します。

Go言語でのポインタの操作は何ですか?

このチュートリアルの動作環境: 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言語でのポインタの操作は何ですか?

Go言語でのポインタの操作は何ですか?

Go は強く型付けされた性質があるため、コードの 3 行目が最も厄介かもしれません。b には a が含まれています。変数のアドレスですが、変数に格納されている値をインクリメントしたいと考えています。

このように、b を逆参照し、代わりにポインタに続く b によって a を参照する必要があります。

次に、値に 1 を加算して、b に格納されているメモリ アドレスに格納し直します。

#最後の行には a の値が出力されます。a の値が 201 に増加していることがわかります

Go言語でのポインタの操作は何ですか?

Go言語でのポインタの操作は何ですか?

##Go 言語の関数パラメータはすべて値のコピーです

変数を変更したい場合は、変数を指すアドレスを作成できます。ポインタ変数 C/C のポインタとは異なり、Go 言語のポインタはオフセットして操作することができず、安全なポインタです。

Go 言語のポインタを理解するには、ポインタ アドレス、ポインタ型、ポインタ値という 3 つの概念を理解する必要があります。

ポインタ アドレスとポインタ型

Go 言語でのポインタ操作は非常に簡単で、次の 2 つの記号を覚えるだけで済みます: & (アドレスを取る) および * (アドレスに基づく値)。

各変数には実行時にアドレスがあり、メモリ内の変数の位置を表します。 Go 言語では、変数の「アドレスを取得」するために、変数の前に & 文字が使用されます。

変数ポインタを取得するための構文は次のとおりです:

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
    }

ポインター演算子Go言語でのポインタの操作は何ですか?

1. ポインター演算子が左辺値の場合、ターゲット オブジェクトの状態を更新できます。右辺値の場合は、ターゲットの状態を取得します。

func main() {
    x := 10
    var p *int = &x  //获取地址,保存到指针变量
    *p += 20        //用指针间接引用,并更新对象
    println(p, *p)  //输出指针所存储的地址,以及目标对象
}

出力:

0xc000040780 30

2. ポインター型は等価演算子をサポートしますが、加算、減算、型変換は実行できません。 2 つのポインタが同じアドレスを指している場合、または両方とも nil である場合、それらのポインタは等しいと見なされます。

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 に変換し、加算および減算演算を実行できますが、不正なアクセスが発生する可能性があります。

ポインタ演算

多くの golang プログラムでは、ポインタは使用されますが、ポインタの加算や減算は行われません。これは C プログラムとは異なります。 。 Golang の公式入門学習ツール (go Tour) には、Go はポインター演算をサポートしていないとさえ記載されています。実際にはそうではありませんが、通常の Go プログラムでポインタ演算を見たことがないようです (まあ、変わったプログラムを書きたいのはわかりますが)。

  • 但实际上,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视频教程编程教学

以上がGo言語でのポインタの操作は何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。