web-dev-qa-db-fra.com

Comment imprimer la valeur du pointeur d'un objet Go? Que signifie la valeur du pointeur?

Je ne fais que jouer avec Go et je n'ai pas encore un bon modèle mental du moment où les structs sont passés par valeur ou par référence.

C'est peut-être une question très stupide mais je veux juste expérimenter un peu et voir si je travaille toujours sur le même objet ou si j'en ai fait une copie (passée par valeur).

Est-il possible d'imprimer le pointeur (ou id interne si la valeur du pointeur est modifiée par gc) d'un objet?

package main

import ( "runtime" )

type Something struct {
    number int
    queue chan int
}

func gotest( s *Something, done chan bool ) {
    println( "from gotest:")
    println( &s )
    for num := range s.queue {
        println( num )
        s.number = num
    }
    done <- true
}

func main() {
    runtime.GOMAXPROCS(4)
    s := new(Something)
    println(&s)
    s.queue = make(chan int)
    done := make(chan bool)
    go gotest(s, done)
    s.queue <- 42
    close(s.queue)
    <- done
    println(&s)
    println(s.number)
}

donne sur mes fenêtres (version compilée 8g):

0x4930d4
from gotest:
0x4974d8
42
0x4930d4
42

Pourquoi la valeur du pointeur dans la routine aller affiche-t-elle une valeur différente? La quantité sur l'objet d'origine a été modifiée pour qu'il fonctionne avec le même objet. Existe-t-il un moyen de voir un identifiant d'objet persistant?

52
Jeroen Dirks

Les arguments de la fonction Go sont passés par valeur.

Commençons par supprimer les parties non pertinentes de votre exemple afin que nous puissions facilement voir que vous ne faites que passer un argument par valeur. Par exemple,

package main

import "fmt"

func byval(q *int) {
    fmt.Printf("3. byval -- q %T: &q=%p q=&i=%p  *q=i=%v\n", q, &q, q, *q)
    *q = 4143
    fmt.Printf("4. byval -- q %T: &q=%p q=&i=%p  *q=i=%v\n", q, &q, q, *q)
    q = nil
}

func main() {
    i := int(42)
    fmt.Printf("1. main  -- i  %T: &i=%p i=%v\n", i, &i, i)
    p := &i
    fmt.Printf("2. main  -- p %T: &p=%p p=&i=%p  *p=i=%v\n", p, &p, p, *p)
    byval(p)
    fmt.Printf("5. main  -- p %T: &p=%p p=&i=%p  *p=i=%v\n", p, &p, p, *p)
    fmt.Printf("6. main  -- i  %T: &i=%p i=%v\n", i, &i, i)
}

Sortie:

1. main  -- i  int: &i=0xf840000040 i=42
2. main  -- p *int: &p=0xf8400000f0 p=&i=0xf840000040  *p=i=42
3. byval -- q *int: &q=0xf8400000d8 q=&i=0xf840000040  *q=i=42
4. byval -- q *int: &q=0xf8400000d8 q=&i=0xf840000040  *q=i=4143
5. main  -- p *int: &p=0xf8400000f0 p=&i=0xf840000040  *p=i=4143
6. main  -- i  int: &i=0xf840000040 i=4143

Dans la fonction main, i est une variable int située à l'emplacement mémoire (&i) 0xf800000040 avec une valeur initiale (i) 42.

Dans la fonction main, p est un pointeur sur une variable int à l'emplacement mémoire (&p) 0xf8000000f0 avec une valeur (p = &i) 0xf800000040 qui pointe vers une valeur int (*p = i) 42.

Dans la fonction main, byval(p) est un appel de fonction qui attribue la valeur (p = &i) 0xf800000040 de l'argument situé à l'emplacement mémoire (&p) 0xf8000000f0 à la fonction byval paramètre q à l'emplacement mémoire (&q) 0xf8000000d8. En d'autres termes, la mémoire est allouée pour le paramètre byvalq et la valeur de l'argument mainbyvalp lui est affectée. les valeurs de p et q sont initialement les mêmes, mais les variables p et q sont distinctes.

Dans la fonction byval, à l'aide du pointeur q (*int), qui est une copie du pointeur p (*int), l'entier *q (i) est défini sur une nouvelle valeur int 4143. À la fin avant de revenir. le pointeur q est défini sur nil (valeur zéro), ce qui n'a aucun effet sur p puisque q est une copie.

Dans la fonction main, p est un pointeur sur une variable int à l'emplacement mémoire (&p) 0xf8000000f0 avec une valeur (p = &i) 0xf800000040 qui pointe vers une nouvelle valeur int (*p = i) 4143.

Dans la fonction main, i est une variable int située à l'emplacement mémoire (&i) 0xf800000040 avec une valeur finale (i) 4143.

Dans votre exemple, la fonction main variable s utilisée comme argument de l'appel de la fonction gotest n'est pas la même que celle de la fonction gotest paramètre s. Elles portent le même nom, mais sont des variables différentes avec des étendues et des emplacements de mémoire différents. Le paramètre de fonction s masque l'argument d'appel de fonction s. C'est pourquoi, dans mon exemple, j'ai nommé l'argument et les variables de paramètre p et q respectivement pour souligner la différence.

Dans votre exemple, (&s) 0x4930d4 est l'adresse de l'emplacement mémoire de la variable s dans la fonction main utilisée comme argument de l'appel de fonction gotest(s, done), et 0x4974d8 est l'adresse de l'emplacement mémoire de la fonction gotest paramètre s. Si vous définissez le paramètre s = nil à la fin de la fonction gotest, cela n'a aucun effet sur la variable s dans main; s in main et s in gotest sont des emplacements mémoire distincts. En termes de types, &s est **Something, s est *Something et *s est Something. &s est un pointeur sur (adresse de l'emplacement mémoire) s, qui est un pointeur sur (adresse de l'emplacement mémoire) une variable anonyme de type Something. En termes de valeurs, main.&s != gotest.&s, main.s == gotest.s, main.*s == gotest.*s et main.s.number == gotest.s.number.

Vous devez suivre les conseils avisés de mkb et cesser d'utiliser println(&s). Utilisez le package fmt, par exemple,

fmt.Printf("%v %p %v\n", &s, s, *s)

Les pointeurs ont la même valeur quand ils pointent vers le même emplacement mémoire. les pointeurs ont des valeurs différentes quand ils pointent vers des emplacements de mémoire différents.

71
peterSO

Dans Go, les arguments sont passés par valeur.

package main

import "fmt"

type SomeStruct struct {
    e int
}

// struct passed by value
func v(v SomeStruct) {
    fmt.Printf("v: %p %v\n", &v, v)
    v.e = 2
    fmt.Printf("v: %p %v\n", &v, v)
}

// pointer to struct passed by value
func p(p *SomeStruct) {
    fmt.Printf("p: %p %v\n", p, *p)
    p.e = 2
    fmt.Printf("p: %p %v\n", p, *p)
}

func main() {
    var s SomeStruct
    s.e = 1
    fmt.Printf("s: %p %v\n", &s, s)
    v(s)
    fmt.Printf("s: %p %v\n", &s, s)
    p(&s)
    fmt.Printf("s: %p %v\n", &s, s)
}

Sortie:

s: 0xf800000040 {1}
v: 0xf8000000e0 {1}
v: 0xf8000000e0 {2}
s: 0xf800000040 {1}
p: 0xf800000040 {1}
p: 0xf800000040 {2}
s: 0xf800000040 {2}
5
peterSO
package main

import "fmt"

func zeroval(ival int) {
     ival = 0
}

func zeroptr(iptr *int) {
     *iptr = 0
}

func main() {
    i := 1
    fmt.Println("initial:", i)
    zeroval(i)
    fmt.Println("zeroval:", i)
    //The &i syntax gives the memory address of i, i.e. a pointer to i.
    zeroptr(&i)
    fmt.Println("zeroptr:", i)
    //Pointers can be printed too.
    fmt.Println("pointer:", &i)
}

SORTIE:

$ go run pointers.go
initial: 1
zeroval: 1
zeroptr: 0
pointer: 0x42131100
1
Jetlum Ajeti
type sometype struct { }
a := sometype {}
b := int(2)
println("Ptr to a", &a)
println("Ptr to b", &b)
1
user181351

Comment puis-je imprimer la valeur du pointeur d'un objet Go?

package main

import (
    "fmt"
)

func main() {
    a := 42
    fmt.Println(&a)
}

résulte en:

0x1040a124

Que signifie la valeur du pointeur?

Selon Wikipedia :

Un pointeur référence un emplacement en mémoire

0
030