4 ms·
The biggest takeaway is the last paragraph: > On most of the machines you're likely to use, "size_t" for loop counters is a good idea where signed values aren'
by rav 10y ago
The biggest takeaway is the last paragraph:
> On most of the machines you're likely to use, "size_t" for loop counters is a good idea where signed values aren't required. It's unsigned and generally as wide as addresses, so there's normally no extra code for zero/sign extends, and the type is standard.
Just work with size_t and be happy!
If you need to iterate through a sequence a[0], a[1], ..., a[n-1] in backwards order, the while-condition "i >= 0" of course won't work with size_t (which is unsigned); instead, use the following idiom:
for (size_t i = n; i--;) f(a[i]);
The above code will call f(a[n-1]), f(a[n-2]), ..., f(a[0]) with no issue, thanks to the post-decrement operator.
- fdej 10y agoQuick: how would you implement for (i = n; i >= 0; i -= k) with unsigned integers? I just use a signed pointer-size type for all sizes and counters, and stay happy...
- tzs 10y agoIf n is not within k of the maximum unsigned integer: i = n+k; do { i -= k; ... } while (i >= k); If n is close enough to the maximum unsigned integer for n+k to overflow: i = n; goto skip_sub; do { i -= k; skip_sub: ... } while (i >= k);
- pbsd 10y agoSomething like for(size_t i = 0; i <= n; i += k) { work_with(n - i); }? This sort of loop always comes up in these discussions, and I was never convinced that signed integers were worth it for that alone.
- Sean1708 10y agoTo be honest I think there are good arguments to both sides, and I don't think there is really a one size fits all solution here. If you use unsigned you've got to pay attention to certain corner cases, if you use signed you've got to pay attention to different corner cases, it's up to you to decide which is more common in your code.
- deleted 10y ago[deleted]
- detrino 10y agoYour loop: void TestSigned(int min, int max, int step) { for (int i = max; i >= min; i -= step) F(i); } Becomes this with unsigned: void TestUnsigned(unsigned min, unsigned max, unsigned step) { while (true) { F(max); if (max < min + step) break; max -= step; } } Now if I want to transform my loop to operate on pointers or iterators, the transformation is trivial: void TestUnsigned(unsigned *min, unsigned *max, unsigned step) { while (true) { F(*max); if (max < min + step) break; max -= step; } } Quick: Do the same for yours.
- dsfuoi 10y agoIt looks easy but it isn't. The second example causes unexpected behavior (and probably ub later) if: min + step > MIN_TYPE_MAX The last example causes undefined behavior if: max - min < step - 1.
- tacos 10y agoIf you up the warnings, you'll even get "signed/unsigned" mismatch if you fail to use size_t with STL containers with gcc.
- CJefferson 10y agoMy bigger problem in the past has been loops of the type: for(int i = 0; i < a-b; ++i) f(a[i]); If a < b, then this works cleanly, with no loops occuring. However: for(unsigned i = 0; i < a-b; ++i) f(a[i]); Instead casts a-b to a large unsigned integer, and horrible things happen. Of course, I could add a pre-check to my loop, but I don't really want to (and of course, I have to remember to do that).
- ape4 10y agoIf its a standard loop, the compiler could replace `int` with `size_t` as an optimization.
- msbarnett 10y agoThis amounts to exploiting undefined overflow. It's literally the optimization the link describes.