struct{}不可取地址,因其无存储位置,仅逻辑复用前字段末尾或结构体起始地址;虽地址看似有规律,但编译器不为其分配独立内存,故&s.empty报错cannot take address。

struct{} 不占内存,但它的地址不是随机的,而是由字段位置和编译器填充规则共同决定——它永远不单独“分配地址”,只依附于前一个非零宽字段的末尾或结构体起始处。
为什么 struct{} 的地址看起来“有规律”但又不能取地址?
Go 中的 struct{} 是零位宽类型(zero-width),unsafe.Sizeof(struct{}{}) == 0,但它仍参与结构体布局。关键点在于:Go 编译器不会为 struct{} 单独分配偏移量,而是复用前一个字段的结束位置(或结构体起始地址)。所以它的“地址”其实是逻辑推导出来的,不是独立分配的。
- 在结构体中,如果
struct{}是第一个字段,它的地址等于结构体变量地址(即偏移 0) - 如果它紧跟在
int64后面,它的地址就是&s.field + 8(假设field是int64) - 但它本身不能取地址:
&s.empty在 Go 1.21+ 会报错cannot take address of s.empty,因为无存储位置
struct{} 在 struct 中的位置如何影响整体 sizeof?
它完全不影响结构体大小,但会影响字段对齐计算中的“边界判断”。例如:
type A struct {
x int64
_ struct{}
y int32
}
这里 y 的偏移不是紧接 x(8 字节后),而是仍从 8 开始——因为 _ struct{} 不引入新对齐约束。但若把 _ 换成 byte,y 就要对齐到 4 字节边界,可能从 12 开始。
-
struct{}不改变最大对齐要求(它对齐值是 1) - 它不触发填充,也不占用空间,因此不会拉大结构体总大小
- 但它让字段顺序更“显式”,有时用于标记语义边界(如区分 header / payload)
数组和切片里 []struct{} 的地址行为
[]struct{} 的底层数组长度为 0 字节,但切片头仍存在:len 和 cap 字段照常存储,data 指针可能为 nil 或指向某个合法地址(如 &struct{}{} 的地址,但该地址不可靠)。
-
make([]struct{}, 100)分配的是 0 字节数据,但切片头占 24 字节(64 位系统) -
unsafe.Slice(&struct{}{}, 100)是未定义行为——因为&struct{}{}本身非法 - 实际中,
[]struct{}常用于信号 channel 或占位,不依赖元素地址
真正容易被忽略的是:哪怕结构体里只有 struct{} 字段,整个 struct 大小仍是 0,但它的地址仍可被传递(比如作为接口值的底层数据),而此时该地址没有对应内存——Go 运行时用特殊标记(如 unsafe.Pointer(uintptr(0x1)))模拟,不指向真实 RAM。


















