代码之家  ›  专栏  ›  技术社区  ›  Jonathan

int16_t如何表示大于32767的数字而不翻转

  •  0
  • Jonathan  · 技术社区  · 2 年前

    在Arduino Uno上运行的这段代码打印递增的数字,并按预期从32767到-32768进行换行。

    int16_t i = 0;
    
    void setup() {
      Serial.begin(115200);
    }
    
    void loop() {
      i++;
      Serial.println(i);
    }
    

    然而,人们认为这段代码在功能上是等效的,它可以打印超过200000个16位数字(有符号或无符号)。

    void setup() {
      Serial.begin(115200);
    
      int16_t i = 0;
    
      while(true) {
        i++;
        Serial.println(i);
      }
    }
    
    void loop() {}
    

    Arduino参考中有关于 int 数据类型。这有关系吗?

    当有符号变量超过其最大或最小容量时,它们会溢出。溢出的结果是不可预测的,因此应该避免这种情况。溢出的一个典型症状是变量从最大容量“滚动”到最小容量,反之亦然,但情况并非总是如此。如果您想要这种行为,请使用unsigned int。

    第二个代码片段中发生了什么?变量是如何明显地表示这么大的数字而不滚动的?

    1 回复  |  直到 2 年前
        1
  •  3
  •   user17732522    2 年前

    将带符号整数增加到其最大值之外,即使其溢出,会导致程序具有未定义的行为。其影响是完全不可预测的。未定义的行为意味着无法保证程序的行为。这个程序可以做任何事情。它甚至不必像人们所期望的那样打印早期的数字。

    编译器会将程序编译为机器指令,假设没有发生带符号整数溢出。如果实际存在溢出,它将发出的指令可能有意义,也可能没有意义。编译器不会试图理解它。

    编译器可能会决定 i 在寄存器中,它可能会比16位宽,并对本地寄存器大小使用增量指令。然后它的增量似乎会超过最大值,因为寄存器可以容纳更大的值。

    或者编译器可能决定使用一些16位加法指令,当加法超过最大大小时,会导致回绕。

    或者编译器可能会注意到你的循环增量超过了最大大小,并删除了整个循环,因为在有效的程序中,你的增量不可能超过最大大小。那么就根本没有输出了。

    或者编译器可能会注意到程序的增量总是超过最大大小,并且编译失败,并出现错误。

    或者编译器可能会执行我没有列出的任何其他操作。