5 ms·
A disadvantage comes to mind. While the following loop works as expected: for (size_t i = 0; i < length; i++) ... The following causes an unsigned integer
by bluetomcat 4y ago
A disadvantage comes to mind. While the following loop works as expected:
for (size_t i = 0; i < length; i++) ...
The following causes an unsigned integer underflow and is an infinite loop:
for (size_t i = length - 1; i >= 0; i--) ...
- ncmncm 4y agoIf you have foolishly turned off -W in your build system, that could happen. Otherwise, you get a nice warning pointing out your folly.
- 10000truths 4y agofor (size_t i = 0; i < length; i++) { size_t j = (length - 1) - i; ... } EDIT: change i to j
- yuliyp 4y agoThat's quite broken (you'd want a different variable inside the body, vs clobbering the iteration counter, else this would process the last item in your list, then exit).
- unwind 4y agoUh no don't reassign the loop variable in the inner scope. Use: const j = (length - 1) - i; in that case. Much safer.
- rabbidruster 4y agoI hope you haven't done this anywhere. Makes my brain hurt, but I think this will only run through the loop one time looking at the last element of the array.
- Banana699 4y agoYou should save the old value of i somewhere and restore it back at the very end of the loop. Or simply define a new j like another comment says.
- xxs 4y agothe correct way/idiom to reverse iterate an array is for (size_t i = length; i-- > 0; )... It's surprising how often the issue pops, it works well with both signed and unsigned integers. (edit) I've started with one based indexing (basic)... mixed with 0 based (assembly), more 1 based (pascal), then more stuff (all zero based). I am, yet, to see a real advantage of a one based indexing... after the initial process.
- empiricus 4y agoIs this cache friendly?
- msk-lywenn 4y agoIt’s not. It was nice on architectures were cache didn’t matter much and were subtracting and comparing to zero was just one instruction (looking at you old core ARM)
- sgtnoodle 4y agoSure, why wouldn't it be? As far as a cache is concerned, I don't think reverse sequential iteration would be any different than forward sequential. The actual RAM accesses may be less optimal if there's some speculative pre-fetching with assumed forward sequential access, but that's conjecture.
- chii 4y agoi would suspect that the cache prefetch/prediction could use the "velocity" of the memory access to predict the next access; so if the access pattern was going backwards, the "velocity" would be negative, but prefetching would still work if they just followed the predicted pattern.
- ehvatum 4y agoWith some exceptions, hardware prefetch works in terms of ascending accesses. To learn if a particular CPU will prefetch for descending access, benchmarking is essential. Best to use soft prefetch calls if performance is critical.
- operator-name 4y agoIn that specific case I'd do the following: for (size_t i = n; i-- > 0 ;) ... Or count from `length` to 1, but subtract 1 in the loop body, or count up and subtract the length in the loop body. Any modern compiler should be able to optimise these to be equivalent. In the majority of cases, counting down is not necessarily. Nor is ordered iteration. Most languages have a `for each` style syntax that's preferable anyway.
- cylon13 4y agoAh yes, the goes-to operator -->
- tomjakubowski 4y agoAnd the wink operator, so the compiler knows you know the deal
- divbzero 4y agoOr alternatively: size_t i = length; while (i--) ...
- jecel 4y agoUnless I am remembering C wrong, this would work but the for (size_t i = length; i-- > 0 ; ) ... that several other people posted would not execute for index 0. Shouldn't it be this instead? for (size_t i = length; --i > 0 ; ) ...
- mananaysiempre 4y agoAs Jens Gustedt points out[1], the following intentional unsigned overflow works perfectly for downwards iteration (even when length is 0 or SIZE_MAX), though it looks a bit confusing at first: for (size_t i = length - 1; i < length; i--) ... You are also free to start at any other (not necessarily in-bounds) index, just like with ascending iteration. [1] https://gustedt.wordpress.com/2013/07/15/a-praise-of-size_t-and-other-unsigned-types/ https://gustedt.wordpress.com/2013/07/15/a-praise-of-size_t-...
- xxs 4y agothe footnote [1] should be [0], just for the sake of this very topic. Seriously though, while the idiom does work for unsigned integers, it's a bad idiom to learn [makes code reviews harder]. The post-decrement one in the loop body works with everything (signed/unsigned), and it's well known.
- 411111111111111 4y agoUh I'm confused but don't know c++. why doesn't that loop end instantly? I mean length - 1 < length should always be true, right? Or does it only terminate when the number underflows? Terribly confused here
- msk-lywenn 4y agoIt’s a condition to run, not a condition to stop
- wizofaus 4y agoThat was my reaction - why should anyone think it might be the latter? Are there languages that do have such a syntax without explicit keywords ("do...until")?
- msk-lywenn 4y agoI think lisp or scheme does. I was often confused by that when I was playing with it
- bregma 4y agoIn the C programming language unsigned integers do not overflow. They wrap. This is well-defined behaviour and the example code is simply incorrect. Most modern compilers will give you a diagnostic for this.
- nemetroid 4y agoUnless wrapping underflow is sensible for the domain (which it isn’t when representing the size of something), unsigned integers are usually a bad idea.
- deleted 4y ago[deleted]
- pwdisswordfish9 4y agoYou can always rip a page out of C++’s playbook: for (size_t i = length; i > 0; i--) { // ... item = array[i - 1]; (This is how reverse iterators work in C++.)