首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用avr++对32b uC中32b的增殖与gcc在X86上的增殖

用avr++对32b uC中32b的增殖与gcc在X86上的增殖
EN

Stack Overflow用户
提问于 2020-02-08 07:57:27
回答 1查看 78关注 0票数 1

问题:

我正在做一个定点c++类,在8b微控制器上执行一些闭环控制系统。

我编写了一个C++类来封装PID,并使用现代gcc编译器在X86桌面上测试了该算法。一切都很好。

当我用现代avr++编译器在8b微控制器上编译相同的代码时,我有一些奇怪的人工制品。经过调试,问题是16b*16b乘法被截断为16b。下面是一些最低限度的代码来展示我想要做的事情。

我在桌面系统上使用了-O2优化,在嵌入式系统上使用了-OS优化,没有其他编译器标志。

代码语言:javascript
复制
#include <cstdio>
#include <stdint.h>

#define TEST_16B    true
#define TEST_32B    true

int main( void )
{
    if (TEST_16B)
    {
        int16_t op1 = 9000;
        int16_t op2 = 9;
        int32_t res;
        //This operation gives the correct result on X86 gcc (81000)
        //This operation gives the wrong result on AVR avr-g++ (15464)
        res = (int32_t)0 +op1 *op2;
        printf("op1: %d | op2: %d | res: %d\n", op1, op2, res );
    }

    if (TEST_32B)
    {
        int16_t op1 = 9000;
        int16_t op2 = 9;
        int32_t res;
        //Promote first operand
        int32_t promoted_op1 = op1;
        //This operation gives the correct result on X86 gcc (81000)
        //This operation gives the correct result on AVR avr-g++ (81000)
        res = promoted_op1 *op2;
        printf("op1: %d | op2: %d | res: %d\n", promoted_op1, op2, res );
    }

    return 0;
}

解决办法:

只要使用局部变量将一个操作数提升到32b,就足以解决这个问题。

我的期望是,C++将以与第一个操作数相同的宽度执行数学操作,因此在我看来,res = (int32_t)0 +...应该告诉编译器,以后发生的任何事情都应该在int32_t分辨率上执行。

事情不是这样的。(int16_t)*(int16_t)操作被截断为(int16_t)。

gcc在一台X86机器上有至少32b的内部字宽,所以这可能是我没有在桌面上看到手工艺品的原因。

AVR指挥线

E:\Programs\AVR\7.0\toolchain\avr8\avr8-gnu-toolchain\bin\avr-g++.exe$(QUOTE) -funsigned-char -funsigned-bitfields -DNDEBUG -I"E:\Programs\AVR\7.0\Packs\atmel\ATmega_DFP\1.3.300\include" -Os -ffunction-sections -fdata-sections -fpack-struct -fshort-enums -Wall -pedantic -mmcu=atmega4809 -B "E:\Programs\AVR\7.0\Packs\atmel\ATmega_DFP\1.3.300\gcc\dev\atmega4809" -c -std=c++11 -fno-threadsafe-statics -fkeep-inline-functions -v -MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -MT"$(@:%.o=%.o)" -o "$@" "$<"

问题:

这是一个兼容的C++编译器的实际预期行为,意味着我做错了,还是这是avr++编译器的一个怪癖?

更新:

各种解决方案的调试器输出

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-02-08 19:04:50

这是编译器的预期行为。

编写A + B * C时,由于运算符优先级的关系,这等同于A + (B * C)B * C术语是独立计算的,不考虑以后将如何使用它。(否则,很难看到C/C++代码,也很难理解到底会发生什么。)

C/C++标准中有整数提升规则,有时通过在执行乘法之前将B和C提升为int类型或unsigned int类型来帮助您。这就是为什么在x86 gcc上得到预期的结果,其中int有32位。但是,由于avr中的int只有16位,整数提升对你来说还不够好。因此,您需要将BC转换为int32_t,以确保乘法的结果也是int32_t。例如,您可以:

代码语言:javascript
复制
A + (int32_t)B * C
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60124970

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档