Skip to content

Instantly share code, notes, and snippets.

@felixge
Created October 18, 2018 19:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save felixge/6ae41cece4b8b9755d1b06ab1740b7ff to your computer and use it in GitHub Desktop.
Save felixge/6ae41cece4b8b9755d1b06ab1740b7ff to your computer and use it in GitHub Desktop.
package main
import "fmt"
func main() {
f1 := &Foo{}
f2 := &Foo{}
fmt.Printf("%p = %p\n", f1, f2)
b1 := &Bar{}
b2 := &Bar{}
fmt.Printf("%p != %p\n", b1, b2)
}
type Foo struct{}
type Bar struct{ Field string }
$ go run main.go
0x1157c08 = 0x1157c08
0xc42000e1e0 != 0xc42000e1f0
WTH? Why wouldn't the pointers be different in both cases?
@mholt
Copy link

mholt commented Oct 18, 2018

Foo, the empty struct, consumes 0 bytes in memory, so their offsets are the same (offset += Foo{} in pointer arithmetic is still offset). But Bar has a field, so it has a slight offset.

This is a subtle difference between pointers and references. Pointers are just numbers; if you have 2 pointers, they'll have different memory addresses, no matter what they point to, and even if they point to the same value or an empty struct; but the empty struct values themselves have the same address in memory, thus their reference is the same offset.

(Edit: As you pointed out on Twitter, the spec leaves it up to the implementation. It's still worth pointing out to that "equal" is not necessarily synonymous with "same", and I still get a headache thinking about it carefully.)

@felixge
Copy link
Author

felixge commented Oct 19, 2018

@mholt yeah, the spec seems to leave it open to the implementation. The latter seems to return a single fixed address for all 0-sized allocations:

	if size == 0 {
		return unsafe.Pointer(&zerobase)
	}

See:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment