& → 左值;能放赋值号左边 → 左值;两者都不行 → 右值一句话:"左值住得久有门牌号(地址),右值是过客没门牌。"
左值 = 有内存地址、可寻址、能放赋值号左边的表达式;右值 = 临时值/纯值,没有可寻址存储,只能放右边。判别方法:能否对它取地址 &。
a、数组元素 arr[0]、解引用 *p、结构体成员 st.member5、运算结果 a+b、函数返回值 f()&a 合法 → a 是左值;&(a+b) 非法 → a+b 是右值++a 返回的还是 a 这个对象 → 左值;a+1 产生临时副本 → 右值arr = other; 非法,常量地址)c = 10; 非法,只读)| 左值 | 右值 | |
|---|---|---|
| 本质 | 有可寻址的存储 | 临时值 / 纯值 |
能取地址 & |
✅ 能 | ❌ 不能 |
| 能放赋值号左边 | ✅ 能 | ❌ 不能 |
| 例子 | 变量、数组元素、*p、成员 |
常量、运算结果、函数返回值 |
int a; int *p = &a; → *p 左值(可 *p = 5);++a 左值(结果还是 a 这个对象)arr → 左值,但不能 arr = other;(常量地址,不可赋值)const int c = 5; → 左值(有地址可 &),但不能 c = 10;(只读)++a 是左值、a+1 是右值:++a 修改并返回 a 这个对象本身(可寻址);a+1 产生一个临时副本,不可取地址a = b 本身是左值(不是右值!)——所以 a = b = c 才能连等:赋值是右结合,先算 b = c(结果仍可寻址),再赋给 a(*(volatile uint32_t*)0x40021000) = 1; 合法正因外层括号让 *解引用 成为左值,可写&a 是左值(它是右值)| 相邻概念 | 和本主题的关系 | 孤立理解会犯的错 |
|---|---|---|
| 指针 | *p 解引用是左值;&a 的结果是右值 |
以为解引用只能读 |
| 数组名 | 数组名是左值但不可赋值(常量地址) | 以为左值都能赋值 |
| const | const 变量是只读左值(可 & 不可写) | 以为 const 不是左值 |
| volatile 寄存器 | 寄存器宏是左值才能被写 | 忘了左值=可写是寄存器的前提 |
2026-08-03
每主题一页,复习时只翻本目录。