v2-on-ui #4

Merged
wandering1 merged 497 commits from v2-on-ui into master 2026-11-02 04:07:13 +08:00
Showing only changes of commit 126c4bf57f - Show all commits
@@ -205,15 +205,18 @@ flowchart TD
代码里写成 `(s_head + SAMPLE_RING_DEPTH - n) % SAMPLE_RING_DEPTH` 而不是 `(s_head - n) % DEPTH`,
是因为后者有两个独立的坑:
- **16 位无符号下溢后再取模不等价**:`s_head < n` 时减法先回绕成 `65536-(n-s_head)`,
而 65536 不是 40 的倍数,`(x mod 65536) mod 40 ≠ x mod 40`。反例 `s_head = 3`、`n = 20`:
正确窗首是 23,回绕后得 65519,`65519 % 40 = 39` → 整窗错位。
- **有符号负取模**:两个 `uint16_t` 先提升成 `int`,`3 - 20 = -17`;C99 的 `%` 向零截断,
`(-17) % 40 == -17`(不是 23),再转回无符号就是一次**越界读**——不报错、不 HardFault。
- **16 位无符号下溢后再取模不等价**:`s_head < n` 时减法先回绕成 `65536-(n-s_head)` = 65521,
而 65536 不是 40 的倍数,`(x mod 65536) mod 40 ≠ x mod 40`。同一个例子:正确窗首是 25,
回绕后 `65521 % 40 = 1` → 整窗错位,读到的是环尾附近。
- **有符号负取模**:两个 `uint16_t` 先提升成 `int`,`5 - 20 = -15`;C99 的 `%` 向零截断,
`(-15) % 40 == -15`(不是 25),再转回无符号就是一次**越界读**——不报错、不 HardFault。
**先加一个 DEPTH** 同时解决两件事:`DEPTH ≡ 0 (mod DEPTH)`,加它不改变同余类、数学值不变;
而 `s_head + DEPTH - n ∈ [0, 2·DEPTH - 2]`,恒非负、远小于 65535,两种整数提升规则下都不下溢。
逐条反例与边界自检(`n == DEPTH` 时 `start == s_head`)见 `App/algo/sample_ring.c` 同名函数的注释。
边界自检:`n == DEPTH` 时 `start == s_head`——环满时「下一拍要覆盖的那格」就是最老点;
未写满时 `s_head == s_filled`,故 `start >= 0`,窗一定不跨环尾。
`App/algo/sample_ring.c` 里只留结论与指向本节的指针,推导以本节为准。
### 5.4 API 契约