在 Arduino Uno 上运行的这段代码会打印递增的数字,并按预期从 32767 回绕到 -32768。
int16_t i = 0;
void setup() {
Serial.begin(115200);
}
void loop() {
i++;
Serial.println(i);
}
Run Code Online (Sandbox Code Playgroud)
然而,人们认为在功能上等效的这段代码不断打印超过 200000 个 16 位数字(有符号或无符号)应该能够表示的数字。
void setup() {
Serial.begin(115200);
int16_t i = 0;
while(true) {
i++;
Serial.println(i);
}
}
void loop() {}
Run Code Online (Sandbox Code Playgroud)
Arduino 参考中有关于数据类型的注释/警告int
。这有关系吗?
当有符号变量超过其最大或最小容量时,它们就会溢出。溢出的结果是不可预测的,因此应该避免这种情况。溢出的典型症状是变量从最大容量“滚动”到最小容量,反之亦然,但情况并非总是如此。如果您想要这种行为,请使用 unsigned int。
第二个代码片段发生了什么?变量如何明显代表这么大的数字而不滚动?
将有符号整数递增到超过其最大值(即溢出)会导致程序出现未定义的行为。其效果是完全不可预测的。未定义的行为意味着无法保证程序将如何运行。该程序可以做任何事情。它甚至不需要像人们所期望的那样打印较早的数字。
假设没有发生有符号整数溢出,编译器会将程序编译为机器指令。如果确实存在溢出,它将发出的指令可能有意义也可能没有意义。编译器不会试图理解它。
编译器可能决定放入i
一个可能比 16 位宽的寄存器,并使用增量指令来确定本机寄存器大小。然后它似乎会增加超过最大值,因为寄存器可以保存更大的值。
或者编译器可能决定使用某些 16 位加法指令,当加法超出最大大小时,会导致回绕。
或者编译器可能会注意到您的循环增量超出了最大大小并删除了整个循环,因为在有效程序中不可能发生增量超出最大大小的情况。那么就根本不会有任何输出。
或者编译器可能会注意到您的程序总是增量超出最大大小,并且无法编译它并出现错误说明。
或者编译器可能会执行我未列出的任何其他操作。
归档时间: |
|
查看次数: |
141 次 |
最近记录: |