¿Lo siguiente provoca un comportamiento indefinido en la línea 4 y/o 5?
#include <stdio.h>
int main(void)
{
char s[] = "foo";
char * p = s - 1; /* line 4 */
printf("%s\n", p + 1); /* line 5 */
return 0;
}
alca
¿Lo siguiente provoca un comportamiento indefinido en la línea 4 y/o 5?
#include <stdio.h>
int main(void)
{
char s[] = "foo";
char * p = s - 1; /* line 4 */
printf("%s\n", p + 1); /* line 5 */
return 0;
}
La disminución del puntero fuera de los límites de la matriz no está definida.
estándar C99 el punto 6.5.6 párrafo 8 dice, en parte,
Cuando una expresión que tiene un tipo entero se suma o se resta de un puntero, el resultado tiene el tipo del operando del puntero. … Si tanto el operando puntero como el resultado apuntan a elementos del mismo objeto de matriz, o uno más allá del último elemento del objeto de matriz, la evaluación no producirá un desbordamiento; de lo contrario, el comportamiento no está definido.
Entonces, su línea 4 está invocando un comportamiento indefinido ya que el resultado no está dentro de la matriz ni está más allá del final.
La frase “la evaluación no producirá” me da curiosidad si el puntero es realmente evaluado. Y el “p + 1” está seguro dentro de la matriz.
– Capitán Jirafa
12 de agosto de 2013 a las 13:31
@CaptainGiraffe: el puntero no se evalúa; la expresión es y da como resultado un puntero (de tipo). En este caso tienes expresión s - 1
cuya evaluación en un contexto dado resulta en algún valor. por ejemplo para C[s -> 00000001]
los s - 1
evalúa a 00000000
. mi lectura es esa evaluación es abstracto aquí y está en el espacio matemático (usted no escribe una expresión que, si se evalúa, daría como resultado …) en lugar de una parte de la ejecución de pasos pequeños.
– Maciej Piechotka
12 de agosto de 2013 a las 13:34
@MaciejPiechotka Sí, su lectura del texto parece coincidir con las otras respuestas. No estoy muy seguro. Tengo la impresión de que evaluar significa mirar ese lugar; UB por supuesto. Después de todo, debería ser aritmética entera regular, comportándose regularmente (razonamiento anecdótico, lo sé).
– Capitán Jirafa
12 de agosto de 2013 a las 13:40
@CaptainGiraffe “Tengo la impresión de que la evaluación significa mirar ese lugar”; su impresión es incorrecta; eso es desreferenciar, no evaluación. Maciej también está equivocado: la evaluación no es abstracta, se refiere al cálculo del valor resultante de la aritmética de punteros.
–Jim Balter
12 de agosto de 2013 a las 13:43
@cmaster No, no es así como funciona. Los compiladores no tienen que buscar un comportamiento indefinido. Nada en el párrafo 8 de 6.5.6 dice que la definición de matriz tiene que ser visible para invocar un comportamiento indefinido.
–Nigel Harper
12/08/2013 a las 20:57
yuhao
¡Sí, la línea 4 tiene un comportamiento indefinido!
C99 6.5.6 Operadores aditivos, Sección 8
Cuando una expresión que tiene un tipo entero se suma o se resta de un puntero, el resultado tiene el tipo del operando del puntero. Si el operando puntero apunta a un elemento de un objeto de matriz, y la matriz es lo suficientemente grande, el resultado apunta a un elemento desplazado del elemento original de tal manera que la diferencia de los subíndices de los elementos de la matriz resultante y original es igual a la expresión entera. En otras palabras, si la expresión P apunta a la
i-th
elemento de un objeto de matriz, las expresiones(P) + N
(equivalentemente,N + (P)
) y(P) - N
(dondeN
tiene el valorn
) apuntan, respectivamente, a lai+n-th
yi−n-th
elementos del objeto de matriz, siempre que existan. Además, si la expresiónP
apunta al último elemento de un objeto de matriz, la expresión(P) + 1
apunta uno más allá del último elemento del objeto de matriz, y si la expresiónQ
apunta uno más allá del último elemento de un objeto de matriz, la expresión(Q) - 1
apunta al último elemento del objeto de matriz. Si tanto el operando puntero como el resultado apuntan a elementos del mismo objeto de matriz, o uno más allá del último elemento del objeto de matriz, la evaluación no producirá un desbordamiento; de lo contrario, el comportamiento no está definido. Si el resultado apunta a uno más allá del último elemento del objeto de matriz, no se utilizará como operando de un elemento unario.*
operador que se evalúa.
Shafik Yaghmour
¿Lo siguiente provoca un comportamiento indefinido en la línea 4 y/o 5?
Sí, Línea 4 es comportamiento indefinido ya que el puntero no apunta dentro de los límites de la matriz o más allá de los límites de la matriz. Aunque es válido apuntar uno más allá de los límites de la matriz, no puede desreferenciar ese elemento.
La sección correspondiente en el proyecto de norma c99 es 6.5.6
Operadores aditivos párrafo 8:
Cuando una expresión que tiene un tipo entero se suma o se resta de un puntero, el resultado tiene el tipo del operando del puntero. […] Si tanto el operando puntero como el resultado señalar elementos del mismo objeto de matriz, o uno más allá del último elemento del objeto de matrizla evaluación no deberá producir un desbordamiento; de lo contrario, el comportamiento no está definido.
El final del párrafo dice que no deberás deferir uno más allá del último elemento:
[…] Si el resultado apunta a uno más allá del último elemento del objeto de matriz, no se utilizará como operando de un operador unario * que se evalúa
Me tomó demasiado tiempo llegar a la especificación, pero sí. Vale la pena señalar que en la práctica esto siempre va a funcionar porque es más difícil hacer que no funcione, pero en teoría no está garantizado.
– chrylis -cautelosamente optimista-
12 de agosto de 2013 a las 12:36
@chrylis Hay intérpretes de C que detendrán la ejecución en la línea 4.
–Jim Balter
12 de agosto de 2013 a las 12:42
@JimBalter Ya tuve que pensar en CINT una vez esta semana… sostiene la cabeza
– chrylis -cautelosamente optimista-
12 de agosto de 2013 a las 12:44
@chrylis: “en la práctica esto siempre va a funcionar” — Esa es una mala suposición. Un compilador optimizador puede suponer que el comportamiento del código está bien definido y transformar el código en función de esa suposición.
–Keith Thompson
12 de agosto de 2013 a las 15:04
@KeithThompson: como caso especial, si el compilador puede determinar estáticamente que una ruta de código conduce incondicionalmente a un comportamiento indefinido, simplemente puede eliminar esa ruta de código completa de la salida, ya que la única forma en que el programa podría evitar tener un comportamiento indefinido es nunca llegar a esa ruta de código.
– R.. GitHub DEJA DE AYUDAR A ICE
13 de agosto de 2013 a las 2:56
Ha pasado un tiempo, pero el duplicado, aunque relacionado, en realidad no parece ser un duplicado de esta pregunta. Podría reabrir, pero como soy la respuesta aceptada, dejaré que otra persona lo haga.
– Shafik Yaghmour
1 oct 2014 a las 12:19
@ShafikYaghmour: “… el duplicado […] en realidad no parece ser un duplicado …“¿Por qué motivo(s), por favor? Por lo que usted (entre otros) responde, la línea 4 en realidad provoca UB, lo mismo hace el
array - 1
en la pregunta vinculada.– alk
1 oct 2014 a las 14:45
Aunque los temas son similares, en realidad no son la misma pregunta, me encuentro más escéptico de los cierres duplicados después de esta meta discusión, pero aparentemente hay una gran divergencia de opinión sobre este tema.
– Shafik Yaghmour
4 de octubre de 2014 a las 1:52
Encontré una situación en la que este comportamiento indefinido en realidad hace que el cálculo sea incorrecto (en un x86 normal): stackoverflow.com/questions/23683029/…
– Bernd Elkemann
28 de enero de 2015 a las 20:13