user2121571
user2121571

Reputation: 1

C: Transforming 'while' loops into 'for' loops

Our codebase contains a few loops of the form while((*assignment*) *condition*), for example:

while((c = *s++) != '\0') {...}

while((i = getNext()) != NULL) {...}

Unfortunately these are causing the compiler to emit an "assignment in condition" warning, which I would like to get rid of. My plan is to transform the while loops into for loops of the form for(assignment; condition; assignment), for example:

for(c = *s++; c != '\0'; c = *s++) {...}

for(i = getNext(); i != 0; i = getNext()) {...}

Is this transformation valid? Is there a better alternative?

Upvotes: 0

Views: 266

Answers (4)

Oak
Oak

Reputation: 471

If my understanding of loops is correct your transformation is completely valid, but this transformation seems to be a lot harder to read than the while loop. Just do the initialization before the while loop and then increment at the end of the loop to get rid of the warning.

c = *s++;
while(c != '\0') 
{
    ...
    c = *s++;
}

Upvotes: 0

paxdiablo
paxdiablo

Reputation: 881243

The transformations are valid, yes, but they result in code that's harder to maintain, simply because there are two places you have to change the assignment.

I would be more inclined to figure out how to turn off that particular warning (even if it's localised with something like the gcc #pragma warning pragma) since it is, after all, perfectly valid C code, both syntactically and (in this case) semantically.

Upvotes: 4

Jim Balter
Jim Balter

Reputation: 16406

You haven't stated what your compiler is, but any compiler of quality allows such a warning to be turned off. But if you can't manage that:

for(;;)
{
    c = *s++;
    if (c == '\0') break;
    ...
}

is equivalent and is more general. Likewise:

for(;;)
{
    i = getNext();
    if (!i) break;
    ...
}

In many cases, better than the first one (but not equivalent) is:

for(;; s++)
{
    c = *s;
    if (c == '\0') break;
    ...
}

These are more verbose and ugly, but they are much better than your transformation that repeats the code, which is fragile and error-prone.

Upvotes: 0

Kerrek SB
Kerrek SB

Reputation: 476970

Personally, I'd write the first loop like this:

for (char c; (c = *s) != '\0'; ++s)
{
    // ...
}

This makes it clear that the s is the thing that's being incremented. You can also omit the != '\0', which is implicit.

I'd keep the second loop as a while loop, or at least leave the assignment-inside-conditional. Maybe like this, to minimize scope pollution:

for (iterator i; i = getNext(); )
{
    // ...
}

I personally find it quite acceptable to have part of the per-loop activity happening inside the conditional; that's natural for things like std::cin >> n and std::getline(file, line), too.

Upvotes: 1

Related Questions