NFR*_*RCR 27 c++ undefined-behavior
以下示例来自Wikipedia.
int arr[4] = {0, 1, 2, 3};
int* p = arr + 5; // undefined behavior
Run Code Online (Sandbox Code Playgroud)
如果我从不取消引用p,那么为什么arr + 5单独的未定义行为?我希望指针表现为整数 - 除了取消引用时,指针的值被视为内存地址.
Luc*_*ore 23
那是因为指针的行为不像整数.它是未定义的行为,因为标准是这样说的.
然而,在大多数平台上(如果不是全部),如果不取消引用数组,则不会发生崩溃或遇到可疑行为.但是,如果你没有取消引用它,那么添加的重点是什么?
也就是说,请注意,在数组末尾的表达式在技术上是100%"正确",并且保证不会因C++ 11规范的§5.75而崩溃.但是,该表达式的结果未指定(只保证不会溢出); 而任何其他表达式超过数组边界超过一个是明确未定义的行为.
注意:这并不意味着从一个一个偏移量读取和写入是安全的.你可能会被修改,不属于该阵列和数据将导致状态/内存损坏.你不会导致溢出异常.
我的猜测就是这样,因为它不仅仅是解除引用错误.还有指针算术,比较指针等.所以更容易说不要这样做,而不是枚举它可能是危险的情况.
MSa*_*ers 15
原始x86可能会出现此类语句的问题.在16位代码上,指针是16 + 16位.如果向低16位添加偏移量,则可能需要处理溢出并更改高16位.这是一个缓慢的操作,最好避免.
在这些系统上,array_base+offset如果偏移量在范围内(<=数组大小),则保证不会溢出.但array+5如果数组只包含3个元素,则会溢出.
这种溢出的结果是你有一个指针,它不会指向数组后面,但之前.这甚至可能不是RAM,而是内存映射硬件.如果构造指向随机硬件组件的指针,即在真实系统上它是未定义的行为,C++标准并不试图限制会发生什么.
“未定义的行为”并不意味着它必须在那行代码上崩溃,但这确实意味着您无法对结果做出任何保证。例如:
int arr[4] = {0, 1, 2, 3};
int* p = arr + 5; // I guess this is allowed to crash, but that would be a rather
// unusual implementation choice on most machines.
*p; //may cause a crash, or it may read data out of some other data structure
assert(arr < p); // this statement may not be true
// (arr may be so close to the end of the address space that
// adding 5 overflowed the address space and wrapped around)
assert(p - arr == 5); //this statement may not be true
//the compiler may have assigned p some other value
Run Code Online (Sandbox Code Playgroud)
我敢肯定,您可以在此处添加许多其他示例。