103 votes

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

Je joue juste avec Go et je n'ai pas encore une bonne idée de quand les structs sont passées par valeur ou par référence.

Cette question peut sembler 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).

Y a-t-il un moyen d'afficher le pointeur (ou l'identifiant interne si la valeur du pointeur est modifiée par gc) d'un objet ?

paquet principal

import ( "runtime" )

type Quelquechose struct {
    nombre int
    file chan int
}

fonction gotest( s *Quelquechose, fait chan bool ) {
    imprimer( "de gotest:")
    imprimer( &s )
    pour num := range s.file {
        imprimer( num )
        s.nombre = num
    }
    fait <- true
}

fonction principale() {
    runtime.GOMAXPROCS(4)
    s := new(Quelquechose)
    imprimer(&s)
    s.file = make(chan int)
    fait := make(chan bool)
    go gotest(s, fait)
    s.file <- 42
    proche(s.file)
    <- fait
    imprimer(&s)
    imprimer(s.nombre)
}

déclenche sur mon windows (version compilée en 8g):

0x4930d4
de gotest:
0x4974d8
42
0x4930d4
42

Pourquoi la valeur du pointeur à l'intérieur de la routine go montre une valeur différente ? La quantité sur l'objet original a bien été modifiée donc cela fonctionnait avec le même objet. Existe-t-il un moyen de voir un identifiant d'objet persistant ?

145voto

peterSO Points 25725

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

Tout d'abord, laissons de côté les parties non pertinentes de votre exemple, afin de pouvoir voir clairement que vous passez simplement 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)
}

Résultat :

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 de type int à l'emplacement mémoire (&i) 0xf800000040 avec une valeur initiale (i) 42.

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

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

Dans la fonction byval, en utilisant le pointeur q (*int), qui est une copie du pointeur p (*int), l'entier *q (i) est configuré avec une nouvelle valeur int 4143. À la fin avant de retourner, 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 vers une variable de type int à l'emplacement mémoire (&p) 0xf8000000f0 avec une valeur (p\=&i) 0xf800000040 qui pointe vers une nouvelle valeur de type int (*p\=i) 4143.

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

Dans votre exemple, la variable de la fonction main s utilisée comme argument pour l'appel de la fonction gotest n'est pas la même que le paramètre de la fonction gotest s. Ils ont le même nom, mais ce sont des variables différentes avec des portées et des emplacements mémoire différents. Le paramètre de la fonction s masque l'argument de l'appel de fonction s. C'est pourquoi dans mon exemple, j'ai nommé les variables d'argument et 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 qui est utilisée comme argument pour l'appel de fonction gotest(s, done), et 0x4974d8 est l'adresse de l'emplacement mémoire du paramètre de la fonction gotest 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 dans main et s dans gotest sont des emplacements mémoire distincts. En termes de types, &s est **QuelqueChose, s est *QuelqueChose, et *s est QuelqueChose. &s est un pointeur vers (adresse de l'emplacement mémoire) s, qui est un pointeur vers (adresse de l'emplacement mémoire) une variable anonyme de type QuelqueChose. En termes de valeurs, main.&s != gotest.&s, main.s == gotest.s, main.*s == gotest.*s, et main.s.number == gotest.s.number.

Vous devriez suivre le sage conseil de mkb et arrêter 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 lorsqu'ils pointent vers le même emplacement mémoire ; les pointeurs ont des valeurs différentes lorsqu'ils pointent vers des emplacements mémoire différents.

13voto

peterSO Points 25725

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

package main

import "fmt"

type SomeStruct struct {
    e int
}

// struct passé par valeur
func v(v SomeStruct) {
    fmt.Printf("v: %p %v\n", &v, v)
    v.e = 2
    fmt.Printf("v: %p %v\n", &v, v)
}

// pointeur vers struct passé par valeur
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)
}

Output:

s: 0xf800000040 {1}
v: 0xf8000000e0 {1}
v: 0xf8000000e0 {2}
s: 0xf800000040 {1}
p: 0xf800000040 {1}
p: 0xf800000040 {2}
s: 0xf800000040 {2}

2voto

type sometype struct { }
a := sometype {}
b := int(2)
println("Pointeur vers a", &a)
println("Pointeur vers b", &b)

1voto

Jetlum Ajeti Points 21
paquet principal

import "fmt"

fonction zeroval(ival int) {
     ival = 0
}

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

fonction principal() {
    i := 1
    fmt.Println("initial:", i)
    zeroval(i)
    fmt.Println("zeroval:", i)
    //La syntaxe &i donne l'adresse mémoire de i, c'est-à-dire un pointeur sur i.
    zeroptr(&i)
    fmt.Println("zeroptr:", i)
    //Les pointeurs peuvent également être affichés.
    fmt.Println("pointeur:", &i)
}

OUTPUT:

$ go run pointers.go
initial: 1
zeroval: 1
zeroptr: 0
pointeur: 0x42131100

1voto

utrecht Points 456

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

package main

import (
    "fmt"
)

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

résultats :

0x1040a124

Que signifie la valeur du pointeur ?

selon Wikipedia:

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X