Skip to content

making a copy of struct and taking address of it returns pointer to the same struct #59341

Not planned
@mobiletoly

Description

@mobiletoly

What version of Go are you using (go version)?

$ go version

1.20.2

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env

GO111MODULE=""
GOARCH="arm64"
GOBIN=""
GOCACHE="/Users/pochkin/Library/Caches/go-build"
GOENV="/Users/pochkin/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/pochkin/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/pochkin/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/opt/homebrew/Cellar/go/1.20.2/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/opt/homebrew/Cellar/go/1.20.2/libexec/pkg/tool/darwin_arm64"
GOVCS=""
GOVERSION="go1.20.2"
GCCGO="gccgo"
AR="ar"
CC="cc"
CXX="c++"
CGO_ENABLED="1"
GOMOD="/Users/pochkin/Projects/my/goquick/templates/golang/db-mongodb/go.mod"
GOWORK="/Users/pochkin/Projects/my/goquick/go.work"
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/f2/smcpzg4s1yq_tc4vfmltrcwh0000gn/T/go-build44889709=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

I have a structure that I pass a pointer to function. Under some conditions I want to create a copy of the structure and get a pointer to it, because I want to modify a copy, not the structure itself. So doing something like this:

v := &(*c)

where "c" is a pointer to a structure.

Seems like "v" points to the same address as "c" and therefore when I modify fields in "v" - it actually modifies these fields in "c" as well (since pointer points to the same address). But if I split it in two different lines, such as

v := *c
v1 := &v

then now I can modify "v1" without affecting "c".

What did you expect to see?

Obviously if I make a copy of structure and take address of it, I would expect for pointer to point to a new structure, not to old one.

I guess some optimization happens when compiler sees &* but it really shouldn't, because developer might have a very clear intent to create a copy of a struct and get a pointer.

Activity

zigo101

zigo101 commented on Mar 31, 2023

@zigo101

*c doesn't mean a copy of c. It means the referenced value of c.

zigo101

zigo101 commented on Mar 31, 2023

@zigo101

*c doesn't mean a copy of c. It means the referenced value of c.

mobiletoly

mobiletoly commented on Mar 31, 2023

@mobiletoly
Author

as per example above:

v := &(*c)

and

v := *c
v1 := &v

it would be reasonable to assume that they should have the same outcome. but in case of first example if you modify v - it modifies c as well. and if you modify v1 - it does not modify c.

how would you document a difference so new developers would understand it easily?

dominikh

dominikh commented on Mar 31, 2023

@dominikh
Member

&*c gets simplified to c, it does not take the address of the result of dereferencing c. This is also the most natural behavior: we take addresses of variables; *c doesn't exist anywhere concrete. (the &Struct{...} literal syntax is a special case, and it's more like an allocation than an address-of operation.)

mobiletoly

mobiletoly commented on Mar 31, 2023

@mobiletoly
Author

I don't think that &*c should be simplified to c, because your intense if very clear - you create a temporary variable by dereferencing *c and then you take an address of it. so for me it does not look like the most natural behavior - because I explicitly insist of (*c) first and then asking for address of this operation. based on my examples above - we are doing pretty much the same - we create a temporary variable. it should be a real clear explanation why &*c gets optimized to just c while if we do:

v := *c
v1 := &v

we will actually get a real copy of c and then a pointer to that newly copied c. otherwise it is so easy to introduce bugs (actually I discovered a bug because of this behavior in my code).

randall77

randall77 commented on Mar 31, 2023

@randall77
Contributor

From the spec:

For an operand x of pointer type *T, the pointer indirection *x denotes the variable of type T pointed to by x.

Note that it does not say "... *x denotes a new variable of type T copied from the variable of type T pointed to by x".
So &*x points to the same variable as x does.

Among other reasons, this is needed so expressions like (*x).foo (more succinctly written as x.foo), change what x points to instead of changing an introduced and immediately thrown away temporary.

seankhliao

seankhliao commented on Mar 31, 2023

@seankhliao
Member

closing as working as intended.

mobiletoly

mobiletoly commented on Apr 2, 2023

@mobiletoly
Author

Thank you for pointing to spec. Appreciate it.

locked and limited conversation to collaborators on Apr 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @dominikh@mobiletoly@randall77@gopherbot@seankhliao

        Issue actions

          making a copy of struct and taking address of it returns pointer to the same struct · Issue #59341 · golang/go