问题
I want the iterator variable in a for loop to reverse iterate to 0 as an unsigned int, and I cannot think of a similar comparison to i > -1, as you would do if it was a signed int.
for (unsigned int i = 10; i <= 10; --i) { ... }
But this seems very unclear, as it is relying on the numerical overflow of the unsigned integer to be above 10.
Maybe I just don't have a clear head, but whats a better way to do this...
Disclaimer: this is just a simple use case, the upper limit of 10 is trivial, it could be anything, and i must be an unsigned int.
回答1:
You can use
for (unsigned int j = n; j-- > 0; ) {}
It iterates from n-1 down to 0.
回答2:
The following does what you want:
for (unsigned i = 10; i != static_cast<unsigned>(-1); --i)
{
// ...
}
This is perfectly defined and actually works. Arithmetic on signed types is accurately defined by the standard. Indeed:
From 4.7/2 (regarding casting to an unsigned type):
If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2^n where n is the number of bits used to represent the unsigned type)
and 3.9.1/4
Unsigned integers, declared unsigned, shall obey the laws of arithmetic modulo 2^n where n is the number of bits in the value representation of that particular size of integer
回答3:
My pattern for this is usually...
for( unsigned int i_plus_one = n; i_plus_one > 0; --i_plus_one )
{
const unsigned int i = i_plus_one - 1;
// ...
}
回答4:
Are you really iterating down from some number greater than std::numeric_limits<int>::max()? If not, I would actually suggest just using a normal int as your loop variable and static_cast it to unsigned in the places in your code that expect it to be unsigned. This way you can use the intuitive >= 0 or > -1 condition and in general I would expect it to be more readable than any of the unsigned alternatives.
The static_cast would just be to tell the compiler how to operate on the variable and have no performance implications at all.
回答5:
I can think the two options are either cast or singed numbers (can be done implicitly be comparing to -1, for example) or use the loop condition to check for overflow like this:
for(unsigned i=10;i>i-1;--i){ } // i = 10, 9, ... , 1
for(unsigned i=10;i+1>i;--i){ } // i = 10, 9, ... , 1,0
This loop will continue until i overflows (meaning that it reached zero). Note that is important that i iterates by 1, or you might end-up with an infinite loop.
回答6:
I would use two variables:
unsigned int start = 10;
for (unsigned int j = 0, i = start; j <= start; ++ j, -- i) {
// ...
}
You can also use a while loop:
unsigned int start = 10;
unsigned int i = start + 1;
while (i --) {
// ...
}
回答7:
for(unsigned i = x ; i != 0 ; i--){ ...
And if you want to execute the loop body when i == 0 and stop after that. Just start with i = x+1;
BTW, why i must be unsigned ?
回答8:
You can try and define the following macro:
#define for_range(_type, _param, _A1, _B1) \
for (_type _param = _A1, _finish = _B1,\
_step = static_cast<_type>(2*(((int)_finish)>(int)_param)-1),\
_stop = static_cast<_type>(((int)_finish)+(int)_step); _param != _stop; \
_param = static_cast<_type>(((int)_param)+(int)_step))
Now you can use it:
for_range (unsigned, i, 10,0)
{
cout << "backwards i: " << i << endl;
}
It can be used to iterate backwards and forwards through unsigned, integers, enums and chars:
for_range (char, c, 'z','a')
{
cout << c << endl;
}
enum Count { zero, one, two, three };
for_range (Count, c, zero, three)
{
cout << "forward: " << c << endl;
}
Despite its awkward definition it is optimized very well. I looked at disassembler in VC++. The code is extremely efficient. Don't be put off but the three for statements: the compiler will produce only one loop after optimization! You can even define enclosed loops:
unsigned p[4][5];
for_range (Count, i, zero,three)
for_range(unsigned int, j, 4, 0)
{
p[i][j] = static_cast<unsigned>(i)+j;
}
You obviously cannot iterate through enumerated types with gaps.
回答9:
I am new to c++, my answer might be realy stupid but, i do this for this kind of reverse loops;
size_t count = 3;
size_t newCount = 0;
if (count > 0)
for (size_t i = count - 1; i >= newCount; i--)
{
//do your work here
//and at the end
if (i == 0)
break;
}
and it works. since "i--" part at the loop executed at the next step, break should work allright. what do you think is this way safe ?
回答10:
Avoiding underflow
unsigned int i = n;
while (i !=0){
--i;
...
}
回答11:
Here is a simple trick to ovoid overflow if i iterates by 1:
for(unsigned int i = n-1; i+1 >= 1; i--) {;}
If you want i to iterate for more than 1:
unsigned int d = 2;
for(unsigned int i = n-1; i+d >= d; i-=d) {;}
回答12:
Just:
int start = 10;
for(unsigned int iPlus1 = start + 1 ; iPlus1 > 0 ; iPlus1--) {
// use iPlus1 - 1 if you need (say) an array index
a[iPlus1 - 1] = 123; // ...
}
No?
回答13:
One more way:
for(unsigned i = n-1; i < n ; --i)
{
// Iterates from n-1 to 0
}
Simillarly for size_t (unsigned integer type) use the same trick
for(std::size_t i = n-1; i < n ; --i)
{
// Iterates from n-1 to 0
}
来源:https://stackoverflow.com/questions/5458204/unsigned-int-reverse-iteration-with-for-loops