Link to home
Start Free TrialLog in
Avatar of dpalyca755
dpalyca755

asked on

complex for loops in c

In a For Loop in C, I have an example where there are multiple conditions separated by commas.
There are 2 initializations, then 2 conditions, then 2 controls.

My question are the conditions separate by commas considered an OR or AND?
I am assuming OR.
ASKER CERTIFIED SOLUTION
Avatar of Infinity08
Infinity08
Flag of Belgium image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Your conditions are however you want them to be just like you would define them in an if statement, The three parts of the for loop are all that's necessary.

EG: for (int i = 5; i < 10 && i >= 5; i++)

You can also have multiple inits and increment/decrements as well as complex variable changing. These will be comma delimited but are always ANDs.
>> These will be comma delimited but are always ANDs.

The comma operator does not perform an AND operation.
No it doesn't, but in the context of this question I meant that all statements will be executed.
I just wanted to avoid any confusion, given that dpalyca755 was using the AND in the sense of a logical AND (as far as I understood it).
I see your point, but the comma delimited statements cannot contain any conditions, so I thought he was wondering if one OR the other got executed or one AND the other.

Anyway, it's all in the details, I think we answered the question, didn't we?
>> but the comma delimited statements cannot contain any conditions

Sure they can. A conditional expression is a valid assignment expression (as the C standard calls it), so it can be an operand to the comma operator.

This works just fine :

        for (i = 20; --i, i > 10;) printf("%d ", i);
Meant "shouldn't". For loops can be as complex as they need be, each comma delimited statement is still executed regardless of the previous one's conditional outcome.

I wouldn't consider --i a "condition" regardless of what the standard calls it. It evaluates to something sure, but in other languages that wouldn't even compile because it's usually an error. That for loop works just fine but it's bad practice.
>> I wouldn't consider --i a "condition"

That's because it isn't, and nobody said it was (although technically, it can be used as a condition, since its result can be used as a boolean value).

The point is that the loop condition in a for loop can be any valid expression. And a comma operator with two operands is a valid expression. As long as the right operand yields a result that can be used as a boolean value, it makes perfect sense (and is entirely valid) that it can be used as the loop condition in a for loop.


>> That for loop works just fine but it's bad practice.

I never have claimed (and will never do so) that this is good practice.
It is however what this question is about, so that's what I'm answering.
Examples for better understanding of comma operator:
1. a = (b = 2, c = 3, d = 4);
    In this, a gets the value 4. (that is the value of the rightmost sub-expression).
2. fun(x, (y=7, y+3), z);
    In this, the 2nd argument passed to fun() uses a comma operator.
    So, the value passed is 10.
    The first part is executed and y gets the value 7. And the 2nd part is executed after that. y is added to 3 and the value returned is 10. This value is passed on.

Hope this clarifies your doubt.
2. fun(x, (y=7, y+3), z);
    In this, the 2nd argument passed to fun() uses a comma operator.
    So, the value passed is 10.

That is correct.
But another subtle point is that the commas between the function arguments are not comma operators, so if it had been
fun(y+2, (y=7, y+3), y+4)
there would be no guarantee whether the y=7 is executed before or after the y+2 or y+4, nor, since the behavior would be undefined, any guarantee that it would execute at all.



> As long as the right operand yields a result that can be used as a boolean value

Besides an aggregate type, is there any possible right operand of a comma operator that cannot be used as a boolean value?
> fun(y+2, (y=7, y+3), y+4)
> there would be no guarantee whether the y=7 is executed before or after the y+2 or y+4, nor, since the
> behavior would be undefined, any guarantee that it would execute at all.
How does it matter, which order the arguments are processed in the above example?
Suppose, y+2 is executed first and then (y=7, y+3) is executed - the 2nd argument will get the value 10.
Suppose, y+4 is executed first and then (y=7, y+3) is executed - the 2nd argument will get the value 10.
So, the value of 2nd argument is not changing, based on the order of evaluation.

Also, I didn't understand the statement "behavior would be undefined, any guarantee that it would execute at all".
May be I am missing some point. So, can you please elaborate?
>> Besides an aggregate type, is there any possible right operand of a comma operator that cannot be used as a boolean value?

Besides aggregate types (which you already mentioned), there is void (or anything returning void, or cast to void).
Sorry, I was just cleaning this and noticed that an important question from ssnkumar had gone unanswered.

>> How does it matter, which order the arguments are processed in the above example?

Ok, I'm going to try and explain this in the simplest way possible to try and make clear why ozo's assertion is true.

The order than function arguments are evaluated is not defined by the standard but they will all be evaluated before the function is called. This is what the ANSI C standard says...

"In preparing for the call to a function, the arguments are evaluated,
and each parameter is assigned the value of the corresponding argument"

"The order of evaluation of the function designator, the actual arguments, and
subexpressions within the actual arguments is unspecified, but there is a sequence point
before the actual call."

So if we look at your example...

fun(y+2, (y=7, y+3), y+4)

and then look at how the compiler might process that line (I say might, because it is undefined, as ozo alludes)...

(y=7 : 7
y+3 : 10)
y+2 : 12
y+4 : 16

Now the function is called, thus...
func(16, 16, 16);

Or it might do this (assume y starts out as 0)...

y+2 : 2
y+4 : 6
(y=7 : 7
y+3 : 9)

Now the function is called, thus...
func(9, 9, 9);

...and so on!

The problem is the compiler can process those arguments in any order, it is compiler specific (or, undefined). Depending on the order and depending on the expressions the results could be different on different compilers, hence the result is undefined.

I hope that makes sense. It's not the easiest thing to understand and it can cause a lot of confusion (even for seasoned C programmers). I've tried to make my explanation as accurate as possible but may have glossed over the exact semantics of the standards definition in favour of clarity.
This question has been classified as abandoned and is closed as part of the Cleanup Program. See the recommendation for more details.