go - 为什么在64位arch中mod 8为4后Go的4bytes对齐结构地址?

标签 go 32bit-64bit memory-alignment

当我研究sync.WaitGroup中的代码时,
我注意到WaitGroup使用state1([3] uint32)字段假定状态原子存储的64位对齐指针。

像这样:

// https://github.com/golang/go/issues/19149
type WaitGroup struct {
    noCopy noCopy
    state1 [3]uint32
}

// state returns pointers to the state and sema fields stored within wg.state1.
func (wg *WaitGroup) state() (statep *uint64, semap *uint32) {
    if uintptr(unsafe.Pointer(&wg.state1))%8 == 0 {
        return (*uint64)(unsafe.Pointer(&wg.state1)), &wg.state1[2]
    } else {
        return (*uint64)(unsafe.Pointer(&wg.state1[1])), &wg.state1[0]
    }
}

但是当我在Mac和Linux上检查时,
在64位系统上,在mod 8之后显示的第一个分配的4字节对齐数据结构地址是 4 ,而在32位系统上,它是 0

我很好奇golang如何保证?

代码在这里:https://play.golang.org/p/oiZMHd2c0I6

// 32-bit system:
// GOARCH=386 go run main.go
// 0 4 0 //why first address mod 8 is 0

// 64-bit system:
// go run main.go
// 4 0 4 //why first address mod 8 is 4

更新:
使用@Renat的答案地址,就不能保证变量地址。
输出可能不包含在内。

最佳答案

golang.org:

计算机体系结构可能需要对齐内存地址;
也就是说,如果变量的地址是某个因子的倍数,则
变量类型的对齐方式
。 Alignof函数接受一个表达式
表示任何类型的变量,并返回(type
的变量(以字节为单位)。

因此,假设Alignof(c)4,它将与4对齐,而不必与8字节对齐。

当创建另一个M对象

var c = M{}
var d = M{}
println(
    unsafe.Sizeof(c),
    unsafe.Alignof(c),
    uintptr(unsafe.Pointer(&c.x))%8,
)
println(
    "    ",
    uintptr(unsafe.Pointer(&d.x))%8,
)

我有:
12 4 4
     0

关于go - 为什么在64位arch中mod 8为4后Go的4bytes对齐结构地址?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60165649/

相关文章:

data-binding - 将结构传递给 Post martini 例程

bundle - 在 64 位机器中创建 32 位 JavaFx Native Bundle

gcc - 了解堆栈对齐强制

c - void* 将具有与指向 char 的指针相同的表示和内存对齐方式

c++ - 原子值的部分比较和完全交换

go - 以通用方式使用 html.ParseFragment

http - Golang negroni 和 http.NewServeMux() 问题

go - 如何将结构分配给接口(interface)

python - 当我创建一个 virtualenv 时,python 以 64 位运行,即使在 OSX 中已经设置为 32 位

php - PHP 中的 32 到 64 位 "Gotchas"