在#define 中相乘会给出奇怪的值

Com*_*tix 0 arduino arduino-c++

我为 Arduino Nano 编写了一个代码,我遇到了这种奇怪的行为:

#define     GREAT      (60 * 60000)
#define     STRANGE     (60 * 6000)
#define     ZERO_X      (60 * 1000)

void setup() {
    Serial.begin(115200);
    Serial.println(GREAT);      // Prints 3600000, that's correct
    Serial.println(STRANGE);    // Prints 32320, thats wrong
    long zerox = ZERO_X;
    Serial.println(zerox);      // Prints -5536, thats also wrong, obviously
}

void loop() {}
Run Code Online (Sandbox Code Playgroud)

到底是怎么回事?

我将 MSVS2019 社区与 vMicro 一起使用

Sla*_*ica 5

您使用整数文字来定义您的值,如文档中所述,文字类型取决于它可以适合的位置。根据规格

在 Arduino Uno(和其他基于 ATmega 的主板)上,一个 int 存储一个 16 位(2 字节)值。

(重点是我的)Arduino Nano 有 2 个字节的 CPU int- 606000并且1000适合有符号整数并使用这种类型。尽管 和 的值60 * 600060 * 1000不能容纳 2 个字节,int因此您会因 UB 和意外值而导致整数溢出。

在另一边60000不适合signed int2 个字节,所以它获得long4 个字节的类型并60000 * 60适合那里,所以你得到预期的结果。要解决您的问题,您只需指定后缀:

#define     GREAT      (60 * 60000L)
#define     STRANGE     (60 * 6000L)
#define     ZERO_X      (60 * 1000L)
Run Code Online (Sandbox Code Playgroud)

并强制它们全部为 type long。没有必要为 做60000,但为了一致性最好有它。

对于您的代码更改:

long zerox = ZERO_X;
Run Code Online (Sandbox Code Playgroud)

这行没有解决问题,因为宏替换后它等于:

long zerox = (60 * 1000);
Run Code Online (Sandbox Code Playgroud)

它没有帮助,因为首先int在初始化的右侧完成了类型的计算,溢出发生然后int被提升到long. 要修复它,您需要转换为 long 参数之一:

 long zerox = 60 * static_cast<long>(1000);
Run Code Online (Sandbox Code Playgroud)

或使用之前建议的后缀。