乍一看,这个问题看起来像是如何检测整数溢出的重复?然而,它实际上是显着不同的.
我发现虽然检测无符号整数溢出非常简单,但在C/C++中检测带符号的溢出实际上比大多数人想象的要困难.
最明显但又天真的方式是这样的:
int add(int lhs, int rhs)
{
int sum = lhs + rhs;
if ((lhs >= 0 && sum < rhs) || (lhs < 0 && sum > rhs)) {
/* an overflow has occurred */
abort();
}
return sum;
}
Run Code Online (Sandbox Code Playgroud)
这个问题是根据C标准,有符号整数溢出是未定义的行为. 换句话说,根据标准,只要您甚至导致签名溢出,您的程序就像取消引用空指针一样无效.因此,您不能导致未定义的行为,然后尝试在事后检测溢出,如上面的后置条件检查示例.
尽管上面的检查很可能适用于许多编译器,但你不能指望它.实际上,因为C标准说未定义有符号整数溢出,所以一些编译器(如GCC)将在设置优化标志时优化上述检查,因为编译器假定有符号溢出是不可能的.这完全打破了检查溢出的尝试.
因此,检查溢出的另一种可能方法是:
int add(int lhs, int rhs)
{
if (lhs >= 0 && rhs >= 0) {
if (INT_MAX - lhs <= rhs) {
/* overflow …Run Code Online (Sandbox Code Playgroud) 我已经阅读了以下规则,并且我一直在尝试编写一个反映一个例子的例子.规则来自3.8/5 N3797:
在对象的生命周期开始之前但是在对象将占用的存储之后,或者在对象的生命周期结束之后以及在重用或释放对象占用的存储之前,任何指向存储的指针之前可以使用对象将位于或位于的位置,但仅限于有限的方式.对于正在建造或销毁的物体,见12.7.否则,这样的指针指的是已分配的存储(3.7.4.2),并且使用指针就像指针的类型一样
void*是明确定义的.允许通过这样的指针的间接,但是得到的左值可以仅以有限的方式使用,如下所述.如果出现以下情况,该程[...]
- 指针用于访问非静态数据成员或调用对象的非静态成员函数,或
[...]
我写的例子:
#include <iostream>
#include <typeinfo>
using std::cout;
using std::endl;
struct A
{
int b = 5;
static const int a = 5;
};
int main()
{
A *p = (A*)0xa31a3442;
cout << p -> a; //1, Well-fromed, there is no compile-time error
cout << p -> b; //2, Segmentation fault is producing
}
Run Code Online (Sandbox Code Playgroud)
这是真的,在的情况下//1很好地形成的,不会造成任何UB的,但//2产生的段错误,这是UB?