5

I want to iterate all possible values of an integer. This code does not work as the termination condition never becomes false:

for (uint32_t i = 0; i <= 0xFFFFFFFF; i++)
    std::cout << i << std::endl;

I've come up with this:

auto loopBody = [](uint32_t value)
{
    std::cout << value << std::endl;
};

uint32_t last = 0xFFFFFFFF;
for (uint32_t i = 0; i < last; i++)
    loopBody(i);

loopBody(last);

It is fairly ugly, though. Is there a prettier way to do this?

Sunius
  • 2,789
  • 18
  • 30
  • Maybe you could use an `int64_t` index and loop to `0x100000000`? – zneak Mar 26 '16 at 19:28
  • Use `std::numeric_limits::max()`. Note that overflow of signed integers is undefined behavior. – kec Mar 26 '16 at 19:32
  • "prettiness" is arbitrary. I think just having the loop and then an extra std::cout statement is cleaner than defining a function to do it. If it bugs you that much, maybe use zneak's suggestion of using a larger datatype that won't overflow. Then if you ever need to loop through the larger datatype you'll have the same problem. – mock_blatt Mar 26 '16 at 19:52
  • amazing this question has so few upvotes. only 4 including mine, after 5 years. there must be a dupe somewhere with more common search terms. @zneak - that approach works if you have int64_t's available. in general I think it would be best to use an approach which does not require a wider data-type than the iteratand (?) . – orion elenzil Dec 07 '21 at 21:40

4 Answers4

5

I would use something like this:

uint32_t i = 0;
do
{
    // Your code here.
    i++;
}
while (i != 0);

I personally find it more elegant than a solution involving std::numeric_limits.


As @NicosC said, keep in mind that you should not do same trick with signed integers, because signed overflow is undefined behavior.
HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
  • 3
    Note that this is UB with signed integers. But it's fine with unsigned. – Nikos C. Mar 26 '16 at 20:18
  • 1
    super minor but personally i'd go with `while (++i != 0)` on the tail there, instead of incrementing `i` inside the loop. altho you do need to be sure that `++i` gets used instead of `i++`. – orion elenzil Dec 07 '21 at 21:39
1

You cannot check for the break condition in the loop header, since for that you would need to exclude the maximum value.

Instead, do the check in the loop body and leave the check in the header empty:

for (auto i = std::numeric_limits<int>::lowest(); ; ++i) {
    std::cout << i << '\n';
    if (i == std::numeric_limits<int>::max())
        break;
}

With a do-while loop, you don't need to check inside the loop body, but you need to move the counter variable to the outer scope, and if you want to avoid undefined behavior, you can only use unsigned integer types:

auto i = std::numeric_limits<unsigned>::lowest();
do {
    std::cout << i << '\n';
} while (i++ < std::numeric_limits<unsigned>::max());

Note that the i++ will overflow, but that only happens after acquiring the current value (we're using postfix increment.) With signed integers however, this overflow would be undefined behavior, and even though we're not using the value after the overflow occurs, undefined behavior can have unpredictable results, even before it actually occurred.

Nikos C.
  • 50,738
  • 9
  • 71
  • 96
1

Well, it call for condition test at the end of the loop, which means using do {} while()

#include <limits>
#include <iostream>

int main() {
    auto beg = std::numeric_limits<unsigned>::lowest();
    auto end = std::numeric_limits<unsigned>::max();

    std::cout << beg << " " << end << std::endl;

    long long count = 0LL;

    auto i = beg;
    do {
        ++count;
        if ((count % (1024LL*1024LL)) == 0)
            std::cout << count << std::endl;
    } while(i++ != end);
    std::cout << count << std::endl;

    return 0;
}
Severin Pappadeux
  • 18,636
  • 3
  • 38
  • 64
0

I would use std::numeric_limits as it states your intent best.

int lowest = std::numeric_limits<int>::lowest();
int max    = std::numeric_limits<int>::max();
for (int i = lowest; i < max; ++i)
   cout << i << '\n';
cout << max << '\n';

or in a function see this Demo

#include <iostream>
#include <limits>
#include <functional>

template <class T>
void for_all(std::function<void(T)> fn)
{
    T lowest = std::numeric_limits<T>::lowest();
    T max    = std::numeric_limits<T>::max();
    for (T i{lowest}; i < max; ++i)
       fn(i);
    fn(max);
}

int main()
{
    for_all<int>([](int i) { 
        std::cout << i << std::endl;
    });
}

Edit: I edited the comparison

Edit 2: See comments. Props to kec ;-)

Maikel
  • 1,204
  • 7
  • 19
  • This results is semi-equivalent generated code as my first code example, which results in an infinite loop. That code is broken. – Sunius Mar 26 '16 at 19:37
  • For signed types, this invokes undefined behavior. But just change it to `<`, and add one more increment. – kec Mar 26 '16 at 19:38
  • True. Shall I delete the answer? – Maikel Mar 26 '16 at 19:40
  • I think it's okay now. May want to add that it will never actually print the maximum value, but that it can be added as another print after the loop. – kec Mar 26 '16 at 19:42
  • No need to use an inefficient `std::function`. – Oktalist Mar 26 '16 at 21:07
  • What is the proper way to wrap a function. Template? – Maikel Mar 26 '16 at 21:08
  • Ok, thanks for that comment. I learned alot by searching for the [difference](http://stackoverflow.com/questions/14677997/stdfunction-vs-template) – Maikel Mar 26 '16 at 21:21