Is there a technical reason to use > (<) instead of != when incrementing by 1 in a 'for' loop?

后端 未结 21 2014
小蘑菇
小蘑菇 2020-12-23 19:48

I almost never see a for loop like this:

for (int i = 0; 5 != i; ++i)
{}

Is there a technical reason to use >

21条回答
  •  無奈伤痛
    2020-12-23 20:29

    I take the adjectival "technical" to mean language behavior/quirks and compiler side effects such as performance of generated code.

    To this end, the answer is: no(*). The (*) is "please consult your processor manual". If you are working with some edge-case RISC or FPGA system, you may need to check what instructions are generated and what they cost. But if you're using pretty much any conventional modern architecture, then there is no significant processor level difference in cost between lt, eq, ne and gt.

    If you are using an edge case you could find that != requires three operations (cmp, not, beq) vs two (cmp, blt xtr myo). Again, RTM in that case.

    For the most part, the reasons are defensive/hardening, especially when working with pointers or complex loops. Consider

    // highly contrived example
    size_t count_chars(char c, const char* str, size_t len) {
        size_t count = 0;
        bool quoted = false;
        const char* p = str;
        while (p != str + len) {
            if (*p == '"') {
                quote = !quote;
                ++p;
            }
            if (*(p++) == c && !quoted)
                ++count;
        }
        return count;
    }
    

    A less contrived example would be where you are using return values to perform increments, accepting data from a user:

    #include 
    int main() {
        size_t len = 5, step;
        for (size_t i = 0; i != len; ) {
            std::cout << "i = " << i << ", step? " << std::flush;
    
            std::cin >> step;
            i += step; // here for emphasis, it could go in the for(;;)
        }
    }
    

    Try this and input the values 1, 2, 10, 999.

    You could prevent this:

    #include 
    int main() {
        size_t len = 5, step;
        for (size_t i = 0; i != len; ) {
            std::cout << "i = " << i << ", step? " << std::flush;
            std::cin >> step;
            if (step + i > len)
                std::cout << "too much.\n";
            else
                i += step;
        }
    }
    

    But what you probably wanted was

    #include 
    int main() {
        size_t len = 5, step;
        for (size_t i = 0; i < len; ) {
            std::cout << "i = " << i << ", step? " << std::flush;
            std::cin >> step;
            i += step;
        }
    }
    

    There is also something of a convention bias towards <, because ordering in standard containers often relies on operator<, for instance hashing in several STL containers determines equality by saying

    if (lhs < rhs) // T.operator <
        lessthan
    else if (rhs < lhs) // T.operator < again
        greaterthan
    else
        equal
    

    If lhs and rhs are a user defined class writing this code as

    if (lhs < rhs) // requires T.operator<
        lessthan
    else if (lhs > rhs) // requires T.operator>
        greaterthan
    else
        equal
    

    The implementor has to provide two comparison functions. So < has become the favored operator.

提交回复
热议问题