为什么越界指针算术的行为不确定?

以下示例来自Wikipedia。


int arr[4] = {0, 1, 2, 3};

int* p = arr + 5;  // undefined behavior

如果我从不取消引用p,那么为什么arr + 5本身是不确定的行为?我希望指针表现为整数-例外,即在取消引用时,指针的值将被视为内存地址。


慕丝7291255
浏览 536回答 3
3回答

慕码人2483693

那是因为指针的行为不像整数。这是未定义的行为,因为标准如此规定。但是,在大多数平台(如果不是全部)上,如果不取消引用数组,则不会崩溃或出现可疑行为。但是,如果您不取消引用它,那么进行添加有什么意义呢?就是说,请注意,从技术上讲,在数组末尾加一个表达式是100%“正确的”,并且保证不会按照C ++ 11规范的5.7节§5崩溃。但是,该表达式的结果是不确定的(只保证不会溢出);而任何其他超出数组界限的表达式都是明确的未定义行为。注意:这并不意味着从一个以上的偏移量进行读写是安全的。您可能将编辑不属于该数组的数据,并会导致状态/内存损坏。您不会导致溢出异常。我的猜测是这样的,因为不仅取消引用是错误的。还有指针算术,比较指针等。因此,说不做而不是列举可能存在危险的情况,更容易说。

慕妹3242003

原始的x86可能与此类语句有关。在16位代码上,指针为16 + 16位。如果将偏移量添加到低16位,则可能需要处理溢出并更改高16位。那是一个缓慢的操作,最好避免。在这些系统上,array_base+offset如果offset在范围内(<=数组大小),则保证不会溢出。但是array+5如果数组仅包含3个元素,则会溢出。溢出的结果是您得到的指针不在数组的后面,而是在数组的后面。那可能甚至不是RAM,而是内存映射的硬件。如果您构造指向随机硬件组件的指针,C ++标准不会尝试限制发生的事情,即在实际系统上是未定义行为。

MMMHUHU

“未定义的行为”并不意味着它必须在该行代码上崩溃,而是意味着您不能保证任何结果。例如:int arr[4] = {0, 1, 2, 3};int* p = arr + 5; // I guess this is allowed to crash, but that would be a rather&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // unusual implementation choice on most machines.*p; //may cause a crash, or it may read data out of some other data structureassert(arr < p); // this statement may not be true&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// (arr may be so close to the end of the address space that&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//&nbsp; adding 5 overflowed the address space and wrapped around)assert(p - arr == 5); //this statement may not be true&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //the compiler may have assigned p some other value我敢肯定,这里还有很多其他例子。
打开App,查看更多内容
随时随地看视频慕课网APP