例如:
size_t x;
...
__builtin_uaddll_overflow(x,1,&x);
无论编译器实现如何,上面的代码都能正确防止整数溢出吗?
到目前为止我所知道的:
size_t
是无符号类型。typedef unsigned long size_t;
可用于定义size_t
。此reference列出的功能是否始终正确?或者它必然取决于具体实施?如果是这样,我怎么能以编程方式选择正确的函数?
答案 0 :(得分:6)
__builtin_uaddll_overflow()
无论编译器实现如何,上面的代码都能正确防止整数溢出吗?
没有。 __builtin_uaddll_overflow()
不是指定的C运算符,也不是C标准库函数。它限制代码选择编译器。 C未指定SIZE_MAX
的功能。
相反,只需针对便携式实现与size_t
进行比较。无论unsigned
与unsigned long
,unsigned
还是其他无符号类型相同,都是可移植的,甚至比size_t x;
size_t y;
if (SIZE_MAX - x < y) Overflow();
else size_t sum = x + y;
更宽或更窄。< / p>
some_unsigned_type
这适用于各种 unsigned 类型 - 甚至是狭窄的类型。始终使用相同的some_unsigned_type x;
some_unsigned_type y;
if (some_unsigned_type_MAX - x < y) Overflow();
else some_unsigned_type sum = x + y;
。
unsigned
使用至少与some_at_least_unsigned_type x;
some_at_least_unsigned_type y;
some_at_least_unsigned_type sum = x + y; // overflow behavior well defined
if (sum < x) {
Overflow();
}
else {
// continue with non-overflowed sum
}
一样宽的无符号类型时,代码可以使用以下内容。
size_t
在size_t
的情况下,unsigned
非常普遍宽于或宽于unsigned
,但未指定为x + y
。
上述内容通常适用于无符号类型,然后比int
更窄。然而,int
用1u*x + y
数学完成,然后独角兽平台可以溢出0u + x + y
数学。 some_unsigned_type
或unsigned
强制数学始终以无符号完成,无论1u*
是否比some_unsigned_type x;
some_unsigned_type y;
some_unsigned_type sum = 1u*x + y; // overflow behavior well defined
if (sum < x) {
Overflow();
}
else {
// continue with non-overflowed sum
}
更窄/更宽。一个好的编译器会发出不执行实际size_t x;
size_t sum = x + 1u; // overflow behavior well defined
if (sum == 0) {
Overflow();
}
else {
// continue with non-overflowed sum
}
乘法的优化代码。
{{1}}
或者在OP的第1个示例中,确保无符号数学添加:
{{1}}