Unsigned int reverse iteration with for loops

纵饮孤独 提交于 2019-11-28 16:50:58
Serge Dundich

You can use

for (unsigned int j = n; j-- > 0; ) {}

It iterates from n-1 down to 0.

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

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;
    // ...
}

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.

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.

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 --) {
    // ...
}
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 ?

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.

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 ?

Avoiding underflow

unsigned int i = n;
while (i !=0){
--i;
...
}

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?

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
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!