-
Notifications
You must be signed in to change notification settings - Fork 17.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
spec: improvement for wording #18950
Comments
Perhaps we can simply say that the alignment of an array is the same as the alignment of the element type of the array. |
This seems inconsistent. Why should an array behave differently than a struct with respect to alignment? If the array is empty, it's alignment could just as well be 1. Then an array (fields are indexed) and a struct (fields are named) behave the same with respect to alignment. |
I think [0]T should aligned the same as T.
The reason is that it's intuitive and also provides a way to force a larger
alignment for a struct:
struct {
_ [0]uint64 // force 64-bit alignment on 64-bit architectures
uint8
}
Also, this is also consistent with other effects of [0]T. For example,
struct {
_ [0]func()
int
}
is not comparable even though there is actually nothing incomparable in the
struct if we adopt the zero size argument.
Finally, unsafe.Alignof([0]T{}) == unsafe.Alignof([1]T{}) is what the
current compilers are implementing.
|
@minux I respectfully disagree with your arguments. 1) There's nothing intuitive about it: An empty array has size 0. There's no reason to force alignment > 1 (see next paragraph). 2) The rules of the type system are independent of alignment and shouldn't be brought in for justification (we make those rules - alignment is forced upon us). Alignment is not a "good onto itself" - it's there to either make direct memory access possible (if unaligned accesses trap), or make it faster. Alignment costs memory and adds complexity. If it were not necessary and if it wouldn't cost not to have it, we'd drop it in a heartbeat. I'd buy the argument that it's simpler (in the spec and the compiler - no need to check for 0 length). But we could absolutely go the other way. I like to see a good example for forced alignment via a _ [0]uint64 field. |
@griesemer I always believed it's the case as @minux described. I'm probably mistaken, but I even think I saw it used in the Go repository. And I'm completely sure I used this to force alignment of C unions translated to Go structs. It even serves as a nice documentation, for example: type foo struct {
_ [0]struct{ // some union
field1 T1
field2 T2
...
}
Union [xx]byte
} |
@cznic I'm not disputing that it's implemented this way, or that the alignment trick is used somewhere (any oddity of a language will be used sooner or later...). My comment was primarily addressing the justification (it's intuitive, or similar what the type system does). The justification (if any) is that it was implemented this way early on, probably because it was simplest (perhaps with or without the alignment trick in mind). But thanks for the example. (I'm a bit sensitive to alignment and related sizing decisions because I don't always agree with the current implementation. See e.g. #14909. I'm painfully aware that we cannot change things.) |
I agree that alignment may cost extra memory and it thus should not be forced unless necessary. I think the interesting question is: How to explicitly force alignment in cases like above? How does CGO solve this problem? |
I don't think memory usage is a valid concern for [0]T.
If you're concerned about the size overhead of adding a [0]T field, then
just don't add it.
cgo basically relies on the fact that (almost) all Go primitive types have
the same alignment rules as C.
and in the rare cases where there're not, if Go has less alignment
requirement than the C counterpart, cgo add explicit padding fields.
And if Go has stricter alignment requirements (e.g. complex types) than the
C code, then cgo will translate the field to [size]byte type.
|
CL https://golang.org/cl/36481 mentions this issue. |
It seems to me that making [1]T and [0]T have different alignments is more complex than leaving them the same. I'd like to leave them the same instead of optimizing (aka special-casing) [0]T. The pending CL seems to do just that - not carve out any special case for [0]T - which is great. |
In the end of the spec, there is a line:
But what about if the length of an array is zero? Then x[0] is illegal. So a better wording would be
Or it is best to add an exception: unsafe.Alignof(zero length array) is always 1. But I found in the latest go, unsafe.Alignof(zero length array) is the same as unsafe.Alignof(a value of the element type of x) .
The text was updated successfully, but these errors were encountered: