在 C 语言中正向遍历数组时,标准模式非常简单:初始化一个 `size_t` 类型的索引为 0,检查其是否小于计数,然后将其递增。然而,尝试将此逻辑镜像到倒序迭代时,往往会导致微妙的错误。一个常见的错误是将索引初始化为 `count - 1` 并检查其是否大于或等于 0。由于 `size_t` 是无符号类型,条件 `i >= 0` 永远为真(恒真式),这可能导致无限循环或越界内存访问。此外,如果计数为 0,表达式 `count - 1` 将回绕到该类型的最大可能值(`SIZE_MAX`),从而导致立即出错。
替代方案,例如切换到 `ssize_t` 等有符号整数类型,虽然可行,但会引入自身的复杂性。有符号整数在 C 表达式的隐式类型转换过程中可能会引起问题,且 `ssize_t` 在所有平台(如 Windows)上都不是标准类型。此外,在 32 位系统上,为大型缓冲区使用有符号整数可能会导致提升或截断问题。这些权宜之计往往会导致复杂的循环头,需要仔细检查以确保逻辑正确,这使得代码更难维护且更容易出错。
David Priver 提出了一种更简洁、符合惯例的解决方案,通过在循环的初始化和条件中使用后置递减运算符来避免这些陷阱。模式 `for (size_t i = count; i--; )` 将 `i` 初始化为总计数。后置递减 `i--` 作为循环条件的一部分被求值;它会递减数值,但返回递减*之前*的值。这确保了第一次迭代使用 `count - 1`(最后一个有效索引),并且当 `i` 在递减前为 0 时循环终止。由于无符号回绕在 C 语言中是定义明确的,当 `i` 在最后一次迭代后从 0 回绕到 `SIZE_MAX` 时,循环会安全终止。这种方法保持了简洁性和可读性,并避免了对有符号类型转换的需求。
