簡體   English   中英

使用 avr-g++ 的 8b uC 中的 32b 乘法 vs 使用 gcc 的 X86 上的 32b 乘法

[英]32b multiplication in 8b uC with avr-g++ vs 32b multiplication on X86 with gcc

問題:

我正在做一個定點 C++ 類來在 8b 微控制器上執行一些閉環控制系統。
我編寫了一個 C++ 類來封裝 PID,並使用現代 gcc 編譯器在 X86 桌面上測試了該算法。 都好。
當我使用現代 avr-g++ 編譯器在 8b 微控制器上編譯相同的代碼時,我得到了奇怪的人工制品。 經過一番調試,問題是16b*16b的乘法被截斷為16b。 下面是一些最小的代碼來顯示我正在嘗試做的事情。

我在桌面系統上使用了 -O2 優化,在嵌入式系統上使用了 -OS 優化,沒有其他編譯器標志。

#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-g++ 編譯器的一個怪癖?

更新:

各種解決方案的調試器輸出演員表比較

這是編譯器的預期行為。

當您編寫A + B * C ,由於運算符優先級的原因,它等效於A + (B * C) B * C項是單獨計算的,不考慮以后將如何使用。 (否則,很難查看 C/C++ 代碼並了解實際會發生什么。)

C/C++ 標准中有整數提升規則,有時可以通過在執行乘法之前將 B 和 C 提升為int類型或unsigned int類型來幫助您。 這就是為什么您在 x86 gcc 上獲得預期結果的原因,其中int有 32 位。 但是,由於 avr-gcc 中的int只有 16 位,因此整數提升對您來說還不夠好。 因此,您需要將BC轉換為int32_t以確保乘法的結果也是int32_t 例如,您可以執行以下操作:

A + (int32_t)B * C

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM