在#define 内相乘给出奇怪的值

Multiplying within #define gives strange values

我为 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() {}

这是怎么回事?

我使用 MSVS2019 Comunity 和 vMicro

您使用整数文字来定义您的值,并且如 documentation type of literal depends on where it can fit. According to specs

中所述

On the Arduino Uno (and other ATmega based boards) an int stores a 16-bit (2-byte) value.

(重点是我的)Arduino Nano 具有 CPU 和 2 个字节 int - 6060001000 适合有符号整数等使用类型。虽然 60 * 600060 * 1000 的值都不能放在 2 个字节中 int 所以你会得到 UB 和意外值的整数溢出。

另一方面,60000 不适合 2 个字节的 signed int,所以它的类型 long 有 4 个字节,60000 * 60 适合那里,所以你得到预期结果。要解决您的问题,您只需指定后缀:

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

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

对于您的代码更改:

long zerox = ZERO_X;

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

long zerox = (60 * 1000);

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

 long zerox = 60 * static_cast<long>(1000);

或按照之前的建议使用后缀。