与 size_t 类型一起使用的正确整数溢出内置函数是什么

What is the correct integer overflow builtin to use with the size_t type

例如:

size_t x;
...
__builtin_uaddll_overflow(x,1,&x);

无论编译器实现如何,上述代码都能正确防止整数溢出吗?

目前我所知道的:

reference 中列出的函数是否始终正确?还是一定要看具体的实现?如果是这样,我如何以编程方式选择正确的函数?

size_t x;
...
__builtin_uaddll_overflow(x,1,&x);

Would the above code correctly guard against integer overflow regardless of compiler implementation?

没有。 __builtin_uaddll_overflow() 不是指定的 C 运算符,也不是 C 标准库函数。它将代码限制为 select 编译器。 __builtin_uaddll_overflow() 的功能未由 C.

指定

相反,只需与 SIZE_MAX 进行比较以获得可移植的实现。无论 size_t 是否与 unsignedunsigned long 或其他一些 unsigned 类型相同,它都是可移植的,甚至比 [=20= 更宽或更窄].

size_t x;
size_t y;
if (SIZE_MAX - x < y) Overflow();
else size_t sum = x + y;

这也适用于各种 unsigned 类型 - 甚至是窄类型。始终使用相同的 some_unsigned_type

some_unsigned_type x;
some_unsigned_type y;
if (some_unsigned_type_MAX - x < y) Overflow();
else some_unsigned_type sum = x + y;

当使用至少与 unsigned 一样宽的 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 宽,尽管没有指定如此.


以上通常适用于比 unsigned 更窄的 unsigned 类型。然而 x + y 是用 int 数学完成的,然后独角兽平台可能会溢出 int 数学。 1u*x + y0u + x + y 强制数学运算始终按 unsigned 进行,无论 some_unsigned_type 是 narrower/wider 还是 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
} 

或者在 OP 的 + 1 示例中,以确保 unsigned 数学加法:

size_t x;
size_t sum = x + 1u;  // overflow behavior well defined
if (sum == 0) {
  Overflow();
}
else {
  // continue with non-overflowed sum
}