在 C 中反向迭代
Iterating Backwards in C

原始链接: https://www.davidpriver.com/Iterating-backwards-in-C.html

在 C 中,许多反向迭代的尝试都会失败:使用无符号索引并写 `i >= 0` 是恒真条件,并会在零处下溢;而改用有符号的 `ssize_t` 则会引入转换、可移植性和提升问题。推荐的惯用法是 `for (size_t i = count; i--; )`,它使用后置递减:循环体看到的索引从 `count-1` 到 `0`,且当之前的值为零时条件停止。无符号回绕是有定义的行为。这保持索引为无符号类型,避免有符号转换问题,并使反向迭代简单且易于验证。

一个 Hacker News 帖子讨论在 C 中反向迭代,并链接到 davidpriver 的文章。评论者讨论一种巧妙的“goes to”风格循环,使用 `while (i --> 0)` 和 `for (size_t i = n; i --> 0;)`。有些人认为它对个人代码足够可读,而另一些人指出 `ssize_t` 兼容性等限制。一位评论者将 VHDL 的 `downto` 循环进行比较,另一位则称赞一个相关的 Brainfuck 项目。页面还包括标准的 Hacker News 导航和 Y Combinator Winter 2027 申请通知。
相关文章

原文
Iterating Backwards in C

Home

David Priver, October 24th, 2026

This is shorter than some of my other posts, but I keep seeing people doing this wrong. It's even worse now in the LLM era.

Let's say you have a buffer and a counter and you need to iterate it backwards for some reason:

_Bool find_last(size_t count, int *haystack,
                int needle, size_t *where);

Almost everyone can do the forward version on autopilot:

for(size_t i = 0; i < count; i++){
  if(haystack[i] == needle){
    *where = i;
    return 1;
  }
}
return 0;

So they try to do the same thing, just iterating backwards:

for(size_t i = count - 1; i >= 0; i--){
  
}

But that doesn't work at all! i >=0 is tautologically true (modern compilers will warn). Even worse, if count is 0, i immediately becomes SIZE_MAX.

Ok, so they try the next version:

for(ssize_t i = count - 1; i >= 0; i--){
  
}

This works in practice with a signed index but introduces some problems:

  • Now your index variable is signed, which can cause problems when used in expressions due to C's conversion rules.
  • ssize_t is a POSIX thing so you'd have to define it yourself on windows.
  • If your type is 32 bit, you run into promotion problems and might even run into truncation problems.
  • This spelling of the loop is overcomplicated and requires special inspection each time. Did you get the second-clause condition right?

Avoiding these problems brings us to the actual, proper way to iterate backwards in C:

for(size_t i = count; i--; ){
  
}

So much simpler! Let's break it down: The key is the postdecrement operator on i. It decrements i but yields the value that i was before the operation. In this case, this means that in the body of the loop i is always in bounds as its value will be decremented after initialization so it is at most count - 1, while the condition checks that if it was previously 0 then the loop ends. i will wrap around, but unsigned wrap-around is well defined in C so that is not a problem.

The final version:

_Bool find_last(size_t count, int *haystack,
                int needle, size_t *where){
  for(size_t i = count; i--; ){
    if(haystack[i] == needle){
      *where = i;
      return 1;
    }
  }
  return 0;
}

Doing it this way means you don't have to mess around with converting to a signed loop index and look at how simple that loop is! You can tell at a glance if someone has implemented the reverse loop properly or not.

So please! If you see someone trying to iterate backwards, show them this way to do it!

All code in this article is released into the public domain.

联系我们 contact @ memedata.com