Inconsistent behavior with pointers to empty struct

Hi,

I was playing around with empty structs struct{} and found some curios behavior, when comparing pointers to empty structs. While I found nothing in the language specification, the compiler seems to optimize all pointers to empty structs to point to the same memory location (irrespective if it is a local or global variable)

So comparing pointers to two empty structs (no matter if they represent different variables) should always return true by this logic? But the compiler also seems to short-circuit local comparisons to pointers and returns false if they represent different variables.

This leads to this inconsistent behavior when comparing the same two pointers once locally and once in a function resulting in different results. Is this a bug? I found nothing in the language specification which would lead me to expect this behavior?

Example on Go Playground

var a struct{}

func main() {
	var b struct{}
	p1, p2 := &a, &b
	fmt.Printf("&a: %p, &b: %p \n", &a, &b)
	fmt.Printf("&a == &b: %v \n", &a == &b)
	fmt.Printf("p1 == p2: %v \n", p1 == p2)
	comp(p1, p2)
}

func comp(p1, p2 any) {
	fmt.Printf("p1 == p2: %v \n", p1 == p2)
}

This prints the same address for &a and &b, but the comparison is false when done in the main method and true when done in the function.

1 Like

Hi @falco467,

That’s indeed a surprising behavior, but it’s not a bug.

The reason for this behavior is that variables may be removed from the call stack and allocated on the heap if certain conditions apply. Then the comparison result may be a different one.

Full explanation: A pitfall of comparing empty structs in Golang - SoByte

Another interesting read: The empty struct | Dave Cheney

The Go spec says: “Two distinct zero-size variables may have the same address in memory.” (Emphasis mine.)

3 Likes

As @christophberger states the spec. does cover this. You cannot rely on the boolean result of comparing pointers to zero-sized variables. But the interesting thing is why you get different results in main and the function. This is due to optimizations in main() I think.

But again I emphasize: you should not write code that relies on comparing addresses to zero-sized variables.

1 Like

You are right. Although the spec is a little vague:

Pointers to distinct zero-size variables may or may not be equal. *

It is not obvious to me that comparing the same two distinct variables multiple times or at different call sites may yield different results. But it is a possible interpretation, so not a bug.

*Go Spec: Comparing pointers

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.