C标准明确规定有符号整数溢出具有未定义的行为。然而,大多数CPU都使用定义的语义为溢出实现签名算法(可能除法除法溢出为:x / 0和INT_MIN / -1)。
编译器的作家一直在走的优势undefinedness这种溢出的补充,往往会打破传统的代码非常微妙的方式更积极的优化。例如,此代码可能在较旧的编译器上有效,但在gccand的当前版本上不再有效clang:
/* Tncrement a by a value in 0..255, clamp a to positive integers.
The code relies on 32-bit wrap-around, but the C Standard makes
signed integer overflow undefined behavior, so sum_max can now
return values less than a. There are Standard compliant ways to
implement this, but legacy code is what it is... */
int sum_max(int a, unsigned char b) {
int …Run Code Online (Sandbox Code Playgroud) 对于这种特殊情况,C 或 C++ 标准对有符号整数除法有何规定?它是否定义以及以何种方式定义?
INT_MIN / -1 (0x8000_0000 / 0xFFFF_FFFF)
Run Code Online (Sandbox Code Playgroud)
数学结果将是0x8000_0000无法用 32 位带符号 2 补码表示的正值。
我的理解是:
看来像下面这样的东西不应该编译,事实上在我的编译器上它不编译。
template<int n> struct S { };
template<int a, int b>
S<a * b> f()
{
return S<a * b>();
}
int main(int, char **)
{
f<50000, 49999>();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但是,现在我尝试以下方法:
#include <numeric>
template<int n> struct S { };
template<int a, int b>
S<std::lcm(a, b)> g()
{
return S<std::lcm(a,b)>();
}
int main(int, char **)
{
g<50000, 49999>();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
g++、clang 和 MSVC 都会愉快地编译它,尽管事实上
如果 |m|、|n| 或 |m| 的最小公倍数,则行为未定义 和|n| 不能表示为 type 的值
std::common_type_t<M, N> …
我刚刚开始学习 MIPS 指令的异常处理程序。
我需要使我的程序具有算术溢出异常,以便我可以测试我的异常处理程序。
我有两个数组 A 和 B。数组 A 有十六进制数,数组 B 有整数。
如何通过添加十六进制数和整数来使溢出?
哪些十六进制数和整数相加会导致溢出?
我试图理解这句话的含义:
(int)(unsigned)-1 == -1;
Run Code Online (Sandbox Code Playgroud)
据我目前的理解,会发生以下事情:
-1是一个有符号的 int并且被转换为无符号的 int。其结果是,由于环绕行为,我们获得了该类型可以表示的最大值unsigned。
接下来,unsigned我们在步骤 1 中获得的这种类型最大值现在被转换为signed int。但请注意,该最大值是一个unsigned type。所以这超出了的范围signed type。并且由于有符号整数溢出是未定义的行为,因此程序将导致未定义的行为。
我的问题是:
PS:我知道如果它是未定义的行为(而不是定义的实现),那么我们不能依赖程序的输出。所以我们不能说我们是否总是会得到true或false。
在 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。
第二个代码片段发生了什么?变量如何明显代表这么大的数字而不滚动?