Description
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 commentedon Mar 31, 2023
*c
doesn't mean a copy ofc
. It means the referenced value ofc
.zigo101 commentedon Mar 31, 2023
*c
doesn't mean a copy ofc
. It means the referenced value ofc
.mobiletoly commentedon Mar 31, 2023
as per example above:
and
it would be reasonable to assume that they should have the same outcome. but in case of first example if you modify
v
- it modifiesc
as well. and if you modifyv1
- it does not modifyc
.how would you document a difference so new developers would understand it easily?
dominikh commentedon Mar 31, 2023
&*c
gets simplified toc
, 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 commentedon Mar 31, 2023
I don't think that
&*c
should be simplified toc
, 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 justc
while if we do:we will actually get a real copy of
c
and then a pointer to that newly copiedc
. otherwise it is so easy to introduce bugs (actually I discovered a bug because of this behavior in my code).randall77 commentedon Mar 31, 2023
From the spec:
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 asx
does.Among other reasons, this is needed so expressions like
(*x).foo
(more succinctly written asx.foo
), change whatx
points to instead of changing an introduced and immediately thrown away temporary.seankhliao commentedon Mar 31, 2023
closing as working as intended.
mobiletoly commentedon Apr 2, 2023
Thank you for pointing to spec. Appreciate it.