【问题标题】:C expression must be a modifiable lvalue (Why am i getting on this expression)C 表达式必须是可修改的左值(我为什么要使用这个表达式)
【发布时间】:2018-08-13 08:12:30
【问题描述】:

我有这个表达式和 ?: operator:

(adc.Voltage1[Counter.ADC_ConversionCount] = ADC_readResult(Handler.myAdc, ADC_ResultNumber_1))  > 10 ? Counter.WriteOut = 1 : Counter.WriteOut = 0;

和 if-else 一样的表达式:

if((adc.Voltage1[Counter.ADC_ConversionCount] = ADC_readResult(Handler.myAdc, ADC_ResultNumber_1)) > 10 ){
    Counter.WriteOut = 1;
}else{
    Counter.WriteOut = 0;
}

为什么在第一种情况下会出现“表达式必须是可修改的左值”错误?

ADC_readResult 函数返回类型为 uint_least16_t。下面是 Counter 结构体定义和 ADC 结构体定义:

typedef struct __COUNTERS__ {
    uint16_t WriteOut;
    uint16_t ADC_ConversionCount;
    uint16_t ADC_CycleCount;
    uint8_t LimitADCReached1;
    uint8_t LimitADCReached2;
    uint8_t LimitADCReached3;
    uint8_t LimitADCReached4;
    uint8_t LimitADCReached5;
} COUNTERS;

typedef struct __ADC_VOLTAGES__ {
    uint16_t Voltage1[ADC_VAL];
    uint16_t Voltage2[ADC_VAL];
    uint16_t Voltage3[ADC_VAL];
    uint16_t Voltage4[ADC_VAL];
    uint16_t Voltage5[ADC_VAL];

} ADC;

【问题讨论】:

  • 就算能编译,写这么复杂难读的表达式也是不好的做法。
  • 仅仅因为您可以在一行中编写一个完整的 C 程序,并不意味着您可以滥用它。你的线太可怕了!易于阅读和解释的代码比作者认为他/她非常聪明地将许多东西塞进一行的代码更易于维护。

标签: c if-statement


【解决方案1】:

您遇到的错误与解析表达式的方式有关。

您的表达式(简化)如下所示:

(a = b) < 10 ? c = 1 : c = 0

三元运算符?: 的优先级高于赋值运算符=。虽然内部的= 被视为三元组的一部分,但最右边的不是。所以表达式解析如下:

((a = b) < 10 ? c = 1 : c) = 0;

结果是您试图将值 0 分配给不是左值的表达式,即变量名或取消引用的指针。你需要括号来解析你想要的方式:

((a = b) < 10) ? (c = 1) : (c = 0);

由于您所做的是基于表达式为c 赋值,因此可以简化如下:

c = ((a = b) < 10) ?  1 : 0;

甚至:

c = ((a = b) < 10);

翻译回您的代码:

Counter.WriteOut = (adc.Voltage1[Counter.ADC_ConversionCount] = ADC_readResult(Handler.myAdc, ADC_ResultNumber_1) > 10);

并通过拆分操作使其更具可读性:

adc.Voltage1[Counter.ADC_ConversionCount] = ADC_readResult(Handler.myAdc, ADC_ResultNumber_1);
Counter.WriteOut = (adc.Voltage1[Counter.ADC_ConversionCount] > 10);

【讨论】:

    【解决方案2】:

    我认为应该是:

    Counter.WriteOut = (adc.Voltage1[Counter.ADC_ConversionCount] = ADC_readResult(Handler.myAdc, ADC_ResultNumber_1)) > 10 ? 1 : 0;
    

    【讨论】:

      【解决方案3】:

      ?: 运算符的优先级高于= 运算符,因此第一个表达式被解释为

      (
        (adc.Voltage1[Counter.ADC_ConversionCount] = ADC_readResult(Handler.myAdc, ADC_ResultNumber_1))  > 10 ?
          Counter.WriteOut = 1 : Counter.WriteOut
      ) = 0
      

      因此,= 的左侧表达式不可修改。

      使用括号来避免这种情况:

      (adc.Voltage1[Counter.ADC_ConversionCount] = ADC_readResult(Handler.myAdc, ADC_ResultNumber_1))  > 10 ? Counter.WriteOut = 1 : (Counter.WriteOut = 0);
      

      Counter.WriteOut = 1 不需要括号,因为它位于 ?: 运算符的中间,没有歧义)

      因为分配的都是普通Counter.WriteOut,所以我更喜欢

      Coumter.WriteOut = ((adc.Voltage1[Counter.ADC_ConversionCount] = ADC_readResult(Handler.myAdc, ADC_ResultNumber_1)) > 10 ? 1 : 0);
      

      或者,使用 C 的比较运算符的定义(它返回 1 表示真,0 表示假),

      Coumter.WriteOut = ((adc.Voltage1[Counter.ADC_ConversionCount] = ADC_readResult(Handler.myAdc, ADC_ResultNumber_1)) > 10);
      

      【讨论】:

        猜你喜欢
        • 2021-09-17
        • 2014-12-15
        • 2014-12-20
        • 2015-09-19
        • 2016-05-09
        • 2016-09-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多