与 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
是无符号类型。
- 根据这个discussion,
typedef unsigned long size_t;
可以用来定义size_t
。
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
是否与 unsigned
、unsigned 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 + y
或 0u + 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
}
例如:
size_t x;
...
__builtin_uaddll_overflow(x,1,&x);
无论编译器实现如何,上述代码都能正确防止整数溢出吗?
目前我所知道的:
- 这 reference 表示
size_t
是无符号类型。 - 根据这个discussion,
typedef unsigned long size_t;
可以用来定义size_t
。
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
是否与 unsigned
、unsigned 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 + y
或 0u + 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
}