【问题标题】:unary operator in avr: undefined behavior?avr中的一元运算符:未定义的行为?
【发布时间】:2021-12-09 09:55:17
【问题描述】:

我的问题是

voltage = voltage*2/3; voltage *= 2/3;

给出了不同的结果。变量为 uint16_t,在 8 位 AVR 微控制器上运行 第一个语句给出了正确的结果,第二个语句总是返回 0

我的一些朋友告诉我,一般不应该使用一元运算符,这让我想到,因为我也使用像 PORTC &= ~(1 << csBit); 这样的东西。对于编译,我使用 avr-gcc 如果这可能会给你一个想法。

提前感谢您的帮助

编辑#1:

好的,我知道 = 不是一元运算符。另外根本的区别是'''='''是从右边开始的,而''''*, /'''是从左边开始的。

我猜对于 uint,两个语句都不正确,我必须写电压 = (uint16_t)((float)voltage*(float)2/3)

感谢@Lundin 指出如何正确回复回复

【问题讨论】:

  • voltage *= 2/3; 等价于voltage = voltage * (2/3)*= 不是一元运算符,它是属于 复合赋值 运算符组的二元运算符。
  • 顺便说一句,1 << ... 几乎总是 8 位和 16 位微控制器上的错误,因为您最终可能会将数据转移到由1 创建的int 类型的符号位中。永远不要对有符号操作数进行按位运算,将1 替换为1u
  • *=+= 等赋值运算符的术语是复合赋值,与直接赋值 运算符= 相对。

标签: c avr avr-gcc unary-operator 8-bit


【解决方案1】:

voltage = voltage*2/3voltage 乘以 2,然后除以 3,并将结果存储在 voltage

voltage *= 2/3 将 2 除以 3,将结果乘以 voltage 并将结果存储在 voltage 中。整数除法被截断,所以2/3 产生零。

这些都不是一元运算符。

【讨论】:

    【解决方案2】:

    你被不同的运算顺序和整数运算的组合所困扰。

    算术运算符是左结合的,所以

    voltage = voltage * 2 / 3;
    

    被解析为

    voltage = (voltage * 2) / 3;
    

    您将voltage * 2 的结果除以3,而

    voltage *= 2 / 3;
    

    等价于

    voltage = voltage * (2 / 3);
    

    您将voltage 乘以2/3 的结果,即0

    问题不在于*=,问题在于

    (a * b) / c != a * (b / c)
    

    【讨论】:

      【解决方案3】:

      区别在于电压=电压*2/3,电压乘以2,结果除以3:

       voltage = 5
       5 * 2 = 10
       10 / 3 = 3
      

      在电压 * = 2 / 3 时,由于您使用的是 uint16_t,因此小数会被截断,它首先执行 2/3,结果乘以电压:

       votage = 5
       2 / 3 = 0
       voltage = 5 * 0 = 0
      

      为避免这种情况,您应该例如在将其分配给电压之前以浮点数运行计算,例如在某处添加“.0”:

       voltage = voltage * 2.0 / 3 = 3
       voltage *= 2.0 / 3 = 3
      

      【讨论】:

      • 在 8 位 AVR 上使用浮点和除法是非常糟糕的建议,因为它没有 FPU,并且会从您的示例中产生非常糟糕的机器代码。只需坚持正确的代码版本即可。如果需要更高的精度,应该用定点算法来解决。
      • 具体示例 voltage *= 2.0 / 3 = 3 不正确 - 它将生成更精确的非整数结果 (3.333...)。不确定OP想要什么;可能不是这个。但无论如何这个想法是好的(对于 OP 以外的其他人)。
      • 啊好的。然后简单地形成电压 *= 2/3;无法使用。
      • @anatolyg:这是不正确的。一旦将结果分配给电压,小数点将被截断(自动转换)
      • @jkbs1337: 电压 = (uint16_t)((float)voltage*(float)2/3);不需要那些重铸,形式应该足够了:电压=电压* 2.0 / 3; (至少它适用于 gcc)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-01
      • 2016-12-21
      • 1970-01-01
      • 1970-01-01
      • 2021-06-11
      • 2014-03-31
      • 2020-10-10
      相关资源
      最近更新 更多