For-loop-insanity

Started by
26 comments, last by FRex 9 years, 8 months ago

Maybe more to the point -- for a local variable, one that will likely be allocated as a register (or on the stack, at worst), you don't really gain anything at all by making 'test' small -- there might be reasons of correctness that are worthwhile, but optimization is basically a non-factor. Maybe if the loop appears in a deeply-recursive function, or on a small, embedded system with 4k of memory or something, but not usually. Just use the natural word-size of the machine, usually plain old 'int' -- it will be as fast as (faster, more likely) than the smaller value.

I totally agree with this. I do usually use int, but sometimes it happens that I want to ensure a certain size just because of the value I am testing against. This is not the case here though. Those cases would more likely be uint64_t, even if I would never make anything that iterates that many times...

Classic mistake. There is a generic way to make it work, if you really want to, though:


uint8_t j = 0;

do
{
  printf("%i\n", j);
}
while (++j);

Which is pretty readable, since the while loop is clearly going to terminate as soon as j overflows. And like Ravyne said, it doesn't really make anything faster in general, that said I personally don't see this as an optimization tactic, but more as a type correctness thing, in other words, the loop variable is going to be used as an 8-bit unsigned integer, so let's not lie to ourselves, make it an 8-bit unsigned integer. But with this comes the responsibility of watching out for overflow and other low-level things which generally don't come up when simply using a sufficiently large signed integer like int, people will have their own opinions on that matter smile.png

edit: fixed the termination condition error, thanks

Ah this is actually quite clever, lol... I would never write anything like that though, but it is a interesting point of view. :D My solution was, of course, to use an int instead.

Advertisement
Since we are trying to come up with new, obscure, and complicated ways for counting up, how about this:

#include <stdio.h>
template<typename Type>
class Range {
    public:
        Range(const Type &first, const Type &last) : m_first(first), m_last(last) { }
        class const_iterator {
            public:
                const_iterator(Type curr) : m_current(curr) { }
                inline const Type &operator*() const { return m_current; }                
                inline bool operator!=(const const_iterator &other) { return m_current != other.m_current; }
                inline const_iterator &operator++() { m_current++; return *this; }
            private:
                Type m_current;
        };
        inline const_iterator begin() const {
            return const_iterator(m_first);
        }
        inline const_iterator end() const {
            return const_iterator(m_last+1);
        }
    private:
        Type m_first, m_last;
};

int main()
{
    for (const auto i : Range<int>(0, 255))
        printf("%i\n", i);
}


Since we are trying to come up with new, obscure, and complicated ways for counting up, how about this

Somehow I can see Java programmer actually doing this.


Since we are trying to come up with new, obscure, and complicated ways for counting up, how about this

Somehow I can see Java programmer actually doing this.

Needs more boilerplate.

At least an ICountUpAble interface to inherit from, and a CountUpFactory object too. It should also parse XML to do the actual counting.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

To be honest, most modern languages have some sort kind of range-based looping constructs...

This is hardly obscure, (x)range in Python works that way.

Lua for loop kind of does too, modifying the iterator doesn't matter, so in meaning it's closer to range like that really.

Anyone who knows range loop syntax could read that easily. Only question is if it's inclusive or not (which is a real problem, as shown in <random> header's distribution classes).

While we are in topic of loops, this is an example from one zlib game codebase I found online:


#define loop(v,m) for(int v = 0; v<int(m); v++)
#define loopi(m) loop(i,m)
#define loopj(m) loop(j,m)
#define loopk(m) loop(k,m)
#define loopl(m) loop(l,m)
#define loopirev(v) for(int i = v-1; i>=0; i--)

Another nice example is trying to count back from size-1 to 0 using int with >=0 condition, and then, (because someone complains that you should always use std::size_t for indices because their holy compiler that clearly never is wrong or stupidly overzealous when ran with -Wall said so) changing type to std::size_t with same condition so it wraps around and never ends.

This is hardly obscure, (x)range in Python works that way.

Lua for loop kind of does too, modifying the iterator doesn't matter, so in meaning it's closer to range like that really.

Anyone who knows range loop syntax could read that easily. Only question is if it's inclusive or not (which is a real problem, as shown in <random> header's distribution classes).

While we are in topic of loops, this is an example from one zlib game codebase I found online:


#define loop(v,m) for(int v = 0; v<int(m); v++)
#define loopi(m) loop(i,m)
#define loopj(m) loop(j,m)
#define loopk(m) loop(k,m)
#define loopl(m) loop(l,m)
#define loopirev(v) for(int i = v-1; i>=0; i--)

Another nice example is trying to count back from size-1 to 0 using int with >=0 condition, and then, (because someone complains that you should always use std::size_t for indices because their holy compiler that clearly never is wrong or stupidly overzealous when ran with -Wall said so) changing type to std::size_t with same condition so it wraps around and never ends.

Why would one redefine the language like that? Too much to type? It is almost like you need to learn a new language inside the language you already know, lol... Unless I completely missed a point.

I guess it's that, the codebase (while technically C++) isn't too commented and is a bit horror-y and very old (10+ years I think) so it's written in very C style with macros, weird casts, relying on memory layout of structs, TONS of globals, etc.

Why would one redefine the language like that? Too much to type? It is almost like you need to learn a new language inside the language you already know, lol... Unless I completely missed a point.

What do you mean? Everyone I know codes in Better C!

Why would one redefine the language like that? Too much to type? It is almost like you need to learn a new language inside the language you already know, lol... Unless I completely missed a point.

What do you mean? Everyone I know codes in Better C!

It actually doesn't look that stupid when you put it like that. biggrin.png

I was thinking to add things like:

#define BEGIN {

#define END }

So it looks a bit more like Pascal too.

This topic is closed to new replies.

Advertisement