¿Por qué el comportamiento aritmético del puntero fuera de los límites es indefinido?

El siguiente ejemplo es de Wikipedia .

int arr[4] = {0, 1, 2, 3}; int* p = arr + 5; // undefined behavior 

Si nunca dejo referencia a p, entonces ¿por qué arr + 5 solo comportamiento indefinido? Espero que los punteros se comporten como enteros, con la excepción de que cuando se desreferencia el valor de un puntero se considera una dirección de memoria.

Eso es porque los punteros no se comportan como enteros. Es un comportamiento indefinido porque el estándar lo dice.

Sin embargo, en la mayoría de las plataformas (si no todas), no se bloqueará ni se ejecutará un comportamiento dudoso si no se desreferencia la matriz. Pero luego, si no lo desreferencia, ¿de qué sirve hacer la sum?

Dicho esto, tenga en cuenta que una expresión que va una sobre el final de una matriz es técnicamente 100% “correcta” y garantiza que no se bloqueará según §5.7 ¶5 de la especificación C ++ 11. Sin embargo, el resultado de esa expresión no está especificado (solo garantiza que no es un desbordamiento); mientras que cualquier otra expresión que vaya más allá de los límites de la matriz es un comportamiento explícitamente indefinido .

Nota: Eso no significa que sea seguro leer y escribir desde un offset de uno por uno. Es probable que esté editando datos que no pertenecen a esa matriz, y causará corrupción de estado / memoria. Simplemente no provocarás una excepción de desbordamiento.

Mi suposición es que es así porque no es solo desreferenciando lo que está mal. También aritmética de punteros, comparación de punteros, etc. Por lo tanto, es más fácil decir que no hagas esto en lugar de enumerar las situaciones en las que puede ser peligroso.

El x86 original puede tener problemas con tales declaraciones. En el código de 16 bits, los punteros son 16 + 16 bits. Si agrega un desplazamiento a los 16 bits inferiores, es posible que tenga que lidiar con el desbordamiento y cambiar los 16 bits superiores. Esa fue una operación lenta y es mejor evitarla.

En esos sistemas, array_base+offset estaba garantizado para no desbordarse, si el desplazamiento estaba dentro del rango (< = tamaño de la matriz). Pero la array+5 se desbordará si la matriz contiene solo 3 elementos.

La consecuencia de ese desbordamiento es que tienes un puntero que no apunta detrás de la matriz, sino antes. Y eso incluso podría no ser RAM, sino hardware mapeado en memoria. El estándar C ++ no intenta limitar lo que sucede si construyes punteros a componentes de hardware aleatorios, es decir, es un Comportamiento Indefinido en sistemas reales.

“Comportamiento no definido” no significa que deba bloquearse en esa línea de código, pero sí significa que no puede garantizar el resultado. Por ejemplo:

 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 

Estoy seguro de que hay muchos otros ejemplos que puedes incluir aquí.

Si arr resulta estar justo al final del espacio de memoria de la máquina, arr+5 podría estar fuera de ese espacio de memoria, por lo que el tipo de puntero podría no ser capaz de representar el valor, es decir, podría desbordarse, y el desbordamiento no está definido.

Algunos sistemas, sistemas muy raros y no puedo nombrar uno, causarán trampas cuando incrementen límites pasados ​​como ese. Además, permite una implementación que proporciona protección de límites para existir … otra vez, aunque no puedo pensar en uno.

Básicamente, no deberías hacerlo y, por lo tanto, no hay ninguna razón para especificar qué sucede cuando lo haces. Especificar lo que sucede supone una carga injustificada para el proveedor de implementación.