这是对问题的完全重写。希望现在已经清楚了。
我想在C中实现一个函数,该函数在溢出的情况下使用包装执行signed int
的添加。
我想主要针对x86-64体系结构,但是当然,实现越容易移植就越好。我还主要关心通过gcc,clang,icc以及Windows上使用的任何东西来生成体面的汇编代码。
目标是双重的:
体面的机器代码是指 native 支持该操作的机器上的单个
leal
或单个addl
指令。我能够满足两个条件之一,但不能同时满足两个条件。
尝试1
我想到的第一个实现是
int add_wrap(int x, int y) {
return (unsigned) x + (unsigned) y;
}
这似乎适用于gcc,clang和icc。但是,据我所知,C标准没有指定从
unsigned int
到signed int
的转换,从而为实现留有余地(另请参见here)。我相信大多数(所有?)主要编译器都可以实现从
unsigned
到int
的预期转换,这意味着它们采用正确的代表模数2 ^ N,其中N是位数,但是标准没有规定,因此不能依赖之后(愚蠢的C标准再次出现)。同样,虽然这是在二进制补码机上执行的最简单的操作,但在一个二进制补码机上却是不可能的,因为存在一个无法表示的类:2 ^(N/2)。尝试2
根据clang docs,可以这样使用
__builtin_add_overflow
int add_wrap(int x, int y) {
int res;
__builtin_add_overflow(x, y, &res);
return res;
}
这应该可以解决clang的问题,因为文档明确指出
问题是他们在GCC docs中说
据我所知,从
long int
转换为int
是特定于实现的,因此我看不到有任何保证会导致包装行为的保证。正如您在[here] [godbolt]中看到的那样,GCC还将生成预期的代码,但是我想确保这并非偶然,并且确实是
__builtin_add_overflow
规范的一部分。icc似乎也可以产生一些合理的结果。
这产生了不错的汇编,但是依赖于内在函数,因此它不是真正符合标准的C。
尝试3
遵循SEI CERT C Coding Standard中那些学究的人的建议。
在他们的CERT INT32-C建议中,他们解释了如何提前检查潜在的溢出。以下是他们的建议:
#include <limits.h>
int add_wrap(int x, int y) {
if ((x > 0) && (y > INT_MAX - x))
return (x + INT_MIN) + (y + INT_MIN);
else if ((x < 0) && (y < INT_MIN - x))
return (x - INT_MIN) + (y - INT_MIN);
else
return x + y;
}
该代码执行正确的检查,并使用gcc编译为
leal
,而不使用clang或icc编译为f
。整个CERT INT32-C建议都是完全垃圾,因为它试图通过迫使程序员执行检查,而该检查首先应作为语言定义的一部分,从而将C转换为“安全”语言。这样做还迫使程序员编写代码,编译器无法再对其进行优化,那么使用C的原因又是什么呢?
编辑
对比在于所生成程序集的兼容性和体面性之间。
例如,对于gcc和clang,应该执行相同操作的以下两个函数被编译为不同的程序集。
两种情况下
g
都不好,两种情况下addl
都很好(jo
+ addl
或cmovnol
+ jo
)。我不知道cmovnol
是否比g
好,但是函数f
始终比ojit_code好。#include <limits.h>
signed int f(signed int si_a, signed int si_b) {
signed int sum;
if (((si_b > 0) && (si_a > (INT_MAX - si_b))) ||
((si_b < 0) && (si_a < (INT_MIN - si_b)))) {
return 0;
} else {
return si_a + si_b;
}
}
signed int g(signed int si_a, signed int si_b) {
signed int sum;
if (__builtin_add_overflow(si_a, si_b, &sum)) {
return 0;
} else {
return sum;
}
}
最佳答案
您完全引用了规则。如果将无符号值转换为有符号值,则结果是实现定义的或引发信号。简而言之,编译器将描述发生的情况。
例如,gcc9.2.0编译器在it's documentation about implementation defined behavior of integers中具有以下内容: