This expression (a-- == 10 && a-- == 9) evaluates left-to-right,
Yes, mostly, but only because && is special.
and a is still 10 at a-- == 10
Yes, because a-- yields the old value.
but a is 9 for a-- == 9.
Yes, because the sequence point at && guarantees the update to a's value is complete before the RHS is evaluated.
1) Is there a clear rule as to when post-increment evaluate?
The best answer, I think, is "no". The side effects due to ++ and -- are completed at some point prior to the next sequence point, but beyond that, you can't say. For well-defined expressions, it doesn't matter when the side effects are completed. If an expression is sensitive to when the side effect is completed, that usually means the expression is undefined.
From this example it seems it evaluates prior to the && but after the ==. Is that because the && logical operator makes a-- == 10 a complete expression, so a is updated after it executes?
Basically yes.
2) Also for c/c++, certain operators such as prefix decrement occur right to left
Careful. I'm not sure what you mean, but whatever it is, I'm almost certain it's not true.
so a == --a first decrements a to 9 and then compares 9 == 9.
No, a == --a is undefined. There's no telling what it does.
Is there a reason for why c/c++ is designed this way?
Yes.
I know for Java, it's the opposite (it's evaluates left to right).
Yes, Java is different.
Here are some guidelines to help you understand the evaluation of C expressions:
Learn the rules of operator precedence and associativity. For "simple" expressions, those rules tell you virtually everything you need to know about an expression's evaluation. Given a + b * c, b is multiplied by c and then the product added to a, because of the higher precedence of * over +. Given a + b + c, a is added to b and then the sum added to c, because+ associates from left to right.
With the exception of associativity (as mentioned in point 1), try not to use the words "left to right" or "right to left" evaluation at all. C has nothing like left to right or right to left evaluation. (Obviously Java is different.)
Where it gets tricky is side effects. (When I said "'simple' expressions" in point 1, I basically meant "expressions without side effects".) Side effects include (a) function calls, (b) assignments with =, (c) assignments with +=, -=, etc., and of course (d) increments/decrements with ++ and --. (If it matters when you fetch from a variable, which is typically only the case for variables qualified as volatile, we could add (e) fetches from volatile variables to the list.) In general, you can not tell when side effects happen. Try not to care. As long as you don't care (as long as your program is insensitive to the order in which side effects matter), it doesn't matter. But if your program is sensitive, it's probably undefined. (See more under points 4 and 5 below.)
You must never ever have two side effects in the same expression which attempt to alter the same variable. (Examples: i = i++, a++ + a++.) If you do, the expression is undefined.
With one class of exceptions, you must never ever have a side effect which attempts to alter a variable which is also being used elsewhere in the same expression. (Example: a == --a.) If you do, the expression is undefined. The exception is when the value accessed is being used to compute the value to be stored, as in i = i + 1.