Is it safe to compute a structure field index based on its address offset (platform/compiler independent)?
type T struct {
F1 int
F2 int
F3 string
F4 float64
F5 bool
}
t := new(T)
t.F1 = 1
t.F2 = 2
t.F3 = "hello wordl!"
t.F4 = 1234.7283823
t.F5 = true
fmt.Println("T address:", &t)
fmt.Println("t.F1 address:", &t.F1, "size: ", unsafe.Sizeof(t.F1), "offset: ", unsafe.Offsetof(t.F1), "value: ", t.F1)
fmt.Println("t.F2 address:", &t.F2, "size: ", unsafe.Sizeof(t.F2), "offset: ", unsafe.Offsetof(t.F2), "value: ", t.F2)
fmt.Println("t.F3 address:", &t.F3, "size: ", unsafe.Sizeof(t.F3), "offset: ", unsafe.Offsetof(t.F3), "value: ", t.F3)
fmt.Println("t.F4 address:", &t.F4, "size: ", unsafe.Sizeof(t.F4), "offset: ", unsafe.Offsetof(t.F4), "value: ", t.F4)
fmt.Println("t.F5 address:", &t.F5, "size: ", unsafe.Sizeof(t.F5), "offset: ", unsafe.Offsetof(t.F5), "value: ", t.F5)
Edit
Maybe the offset word makes the question a bit confusing. When the above code is run the address space is growing. What I want to know exaclty is if the struct fields are allocated in the order of their definition.
"Is it safe" well, let me stop you there. You're using a package called unsafe.
"Can this generally be expected to work assuming no radical changes are made to things like the Garbage Collector?" Yeah, probably.
From the unsafe
documentation for OffsetOf
:
Offsetof returns the offset within the struct of the field represented by v, which must be of the form structValue.field. In other words, it returns the number of bytes between the start of the struct and the start of the field.
In other words, it's guaranteed to take into account issues of alignment and such. unsafe.Pointer(uintptr(&t) + unsafe.OffsetOf(t.F1))
is guaranteed to be the actual unsafe pointer to the actual unsafe address of the field F1
of that specific instance of t
at that precise moment in time.
You still have to be very careful about unsafe
, unsafe pointers don't generally count as "references" to an object for garbage collection purposes. So if your only reference to that object is that unsafe pointer to that field... weird things may happen. In addition, there's been talk of implementing a "compacting GC" which means that on Garbage Collection memory may be shuffled around, which means that unless you pin the object (which will be added with the compacting GC), the unsafe pointer could spontaneously become invalid without you knowing (regular pointers would remain in tact of course).
If you're sure you'll keep a reference to it, and you're okay with future changes totally breaking your code, go for it. I mean, make absolutely sure you need to use unsafe, but if you've deemed this is the best or only possible solution to your problem, go for it assuming you accept those risks.
Edit: As for "memory order" business. Well, let's just say that I can't find a reference in the spec that guarantees structs are laid out in field order. That said, certain things like encoding/binary.Read
would make... shall we say... less than a lot of sense if they weren't.
So don't "rely on it" in a super technical sense, but for any mainstream Go compiler, you can probably be assured fields are in memory order -- with all the usual caveats about word alignment and packing that brings.
Maybe the offset word makes the question a bit confusing. When the above code is run the address space is growing. What I want to know exaclty is if the struct fields are allocated in the order of their definition.
This should generally hold, but watch out for corner cases like this:
type foo struct {
a int
b [0]byte
c int
}
Also, Go technically doesn't guarantee this. I don't see any reason why any standard Go implementation would change the field-order. Notice however, that there are non-standard implementations (e.g. some implementations that compile Go code to JavaScript) of the Go runtime that do not implement structs as consecutive memory locations, where the notion of unsafe.Offsetof
becomes meaningless. These implementations don't provide the unsafe
package as far as I know, so your code will not compile anyway.
TL;DR: Yes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With