What is wrong with this assignment in a conditional operator?

前端 未结 4 998
独厮守ぢ
独厮守ぢ 2021-01-15 09:18

There is an error. Is it wrong to assign a value to a[i] in the following code? Or something is wrong with conditional operators?

#include
#in         


        
相关标签:
4条回答
  • 2021-01-15 09:40

    This is a bit tricky. There's a nice overview of "effective" operator precedence in C and I'll cite the notes from there explaining your problem *):

    There is a part of the grammar that cannot be represented by a precedence table: an assignment-expression is not allowed as the right hand operand of a conditional operator, so e = a < d ? a++ : a = d is an expression that cannot be parsed, and therefore relative precedence of conditional and assignment operators cannot be described easily.
    However, many C compilers use non-standard expression grammar where ?: is designated higher precedence than =, which parses that expression as e = ( ((a < d) ? (a++) : a) = d ), which then fails to compile due to semantic constraints: ?: is never lvalue and = requires a modifiable lvalue on the left.

    After DavidBowling's findings in the standard (thanks for this work!), the second paragraph above is not entirely correct, or, at least a bit confusing. It's correct that the right-hand operand of ?: cannot be an assignment, but the middle operand can. So for the right-hand side, the ?: "takes precedence" over =, while it doesn't for the middle part. Any part can be a primary expression, therefore paranthesizing to "change precedence" works as expected:

    a[i]>90 ? a[i]=a[i]-32 : (a[i]=a[i]+32);
    

    But, as others have stated, this is needlessly complex anyways, you can achieve what you want with just

    a[i] += a[i]>90 ? -32 : 32;
    

    which is also easier to understand.


    *) To understand the reasoning in this citation, you have to know that lvalue is used in the C standard to describe something that might appear on the left hand side (hence the name) of an assignment (aka can be assigned to). This is a somewhat sloppy definition and is clarified further in the C standard, I think it's enough for the context of this answer.

    0 讨论(0)
  • 2021-01-15 09:42

    a[i]>90 ? a[i]=a[i]-32 : a[i]=a[i]+32;

    is not evaluated as

    a[i]>90 ? (a[i]=a[i]-32) : (a[i]=a[i]+32);

    since = has lower precedence than ?:. In standard C you can't write it as above although some compilers allow it as an extension.

    You could write it as the more readable (and portable)

    a[i] += a[i] > 90 ? -32 : +32;
    
    0 讨论(0)
  • 2021-01-15 09:48

    This is really a matter of understanding the syntax of the conditional operator. This is spelled out in §6.5.15 of the C11 Standard:

    conditional-expression:
    logical-OR-expression
    logical-OR-expression ? expression : conditional-expression

    Thus, the third operand to the conditional operator must be a conditional-expression. Tracing the possibilities for conditional expressions through the grammar defined in the Standard, one finds that an assignment expression is not one of the options. The relevant syntax definitions are found in §6.5 Expressions.

    By following the chain of possibilities from conditional-expression all the way back to primary-expression, it can be seen that a conditional-expression may be a logical-OR-expression, or a logical-AND-expression, or an inclusive-OR-expression, or an exclusive-OR-expression, or an AND-expression, or an equality-expression, or a relational-expression, or a shift-expression, or an additive-expression, or a multiplicative expression, or a cast-expression, or a unary-expression, or a postfix-expression, or a primary-expression. A primary-expression is an identifier, a constant, a string-literal, an ( expression ), or a generic-selection.

    So, an assignment-expression (which may be a conditional expression) is not on the list of possibilities for a conditional expression. This is the reason for the error reported in the question: since an assignment expression is not valid syntax here, the statement:

    a[i]>90 ? a[i]=a[i]-32 : a[i]=a[i]+32;
    

    is interpreted as:

    (a[i]>90 ? a[i]=a[i]-32 : a[i]) = a[i]+32;
    

    The left side of the above assignment expression is not a modifiable lvalue, as required for an assignment expression, hence the error.

    But, note that a parenthesized expression of the form ( expression ) is a valid conditional-expression, and an assignment-expression is an expression. So, this is a legal statement:

    a[i]>90 ? a[i]=a[i]-32 : (a[i]=a[i]+32);
    

    All of that said, this is probably not the right way to code this. Better to use one of the alternatives proposed in other answers, such as:

    a[i] += a[i] > 90 ? -32 : 32;
    
    0 讨论(0)
  • 2021-01-15 09:50

    Use = once in your statement, since it has lower precedence over ?:. Something like:

    a[i] = a[i] > 90 ? a[i] - 32 : a[i] + 32;

    0 讨论(0)
提交回复
热议问题