C语言 用于size_t类型的正确整数溢出内置



例如:

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

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

到目前为止,我所知道的:

  • 此引用指出size_t是无符号类型。
  • 根据此讨论,typedef unsigned long size_t;可用于定义size_t

此参考中列出的函数是否始终正确?还是必然取决于具体的实现?如果是这样,如何以编程方式选择正确的函数?

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

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

不。__builtin_uaddll_overflow()不是指定的 C 运算符,也不是 C 标准库函数。 它限制代码选择编译器。__builtin_uaddll_overflow()的功能不是由 C 指定的。

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

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

这也适用于各种无符号类型 - 甚至是狭窄的类型。 始终使用相同的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一样宽的无符号类型时,代码可以使用以下内容。

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数学,独角兽平台可能会溢出数学int1u*x + y0u + 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
} 

或者在 OP 的 + 1 示例中,为了确保无符号数学加法:

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

最新更新