【发布时间】:2020-02-15 07:30:17
【问题描述】:
在 C 和 C++ 中,size_t 是用于表示大小的无符号类型。它表达了意图并在某种程度上简化了范围断言(len < upper_bound vs len >= 0 && len < upper_bound 用于有符号整数)。
(在下面的所有示例中,len 表示数组的长度a)。
for 循环的习惯用法是:for (i = 0; i < len; i++)。向后 for 循环的习惯用法是 for (i = len-1; i >= 0; i--)。但是无符号循环索引会引入一些细微的错误,而且我经常会弄乱边缘情况。
首先,反向 for 循环。此代码在 len=0 时下溢。
for (size_t i = len-1; i >= 0; i--) { // Bad: Underflows for len=0
use(a[i]);
}
这里有个-->“操作员”的把戏,如果你不习惯的话,看起来很奇怪。
for (size_t i = len; i--> 0;) {
use(a[i]);
}
您可以对循环索引变量使用有符号类型,但如果len > INT_MAX 则会溢出。许多人和组织认为这种风险非常小,所以他们只坚持int。
for (int i = len-1; i >= 0; i--) { // BAD: overflows for len < INT_MAX
use(a[i]);
}
所以我决定采用这种结构,因为它最接近典型的 for 循环形式并且具有最简单的表达式。
for (size_t i = len; i > 0; i--) {
size_t pos = i-1;
use(a[pos]);
}
我的问题从 0 迭代到 len-1
也就是说,在范围 [0, len-1) 上循环。当len=0 时,此循环下溢。
for (size_t i = 0; i < len-1; i++) { // BAD: Underflows for len=0.
use(a[i]);
}
对于向后迭代的情况,你可以使用有符号整数,但这可能会导致溢出。
for (int i = 0; i < len-1; i++) { // BAD: Will overflow if len > INT_MAX
use(a[i]);
}
我倾向于在循环条件中添加另一个表达式,检查len > 0,但这感觉很笨拙。
for (size_t i = 0; len > 0 && i < len-1; i++) {
use(a[i]);
}
我可以在循环之前添加一个 if 语句,但这也感觉很笨拙。
有没有更简单的方法来编写一个无符号索引变量从 0 循环到 len-1 的 for 循环?
【问题讨论】:
-
为什么不在循环前检查 len > 0 和其他边界?
-
关于
-->操作符,中间加一个空格,就不会那么奇怪了。 -
我愿意
for (size_t i = len-1; i != (size_t)-1; i--)。 -
请注意
for (size_t i = len-1; i >= 0; i--)是一个无限循环。 -
即使
len > 0,您的第一个示例也是错误的。问题是i >= 0总是正确的。
标签: c++ c for-loop unsigned size-t