Soy nuevo en la programación C y estoy luchando mucho para entender por qué esto funciona
#include <stdio.h> int main() { int l = -5; char arr[l]; printf("content: %s; sizeof: %d\n", arr, sizeof(arr)); }con salida:
content: ; sizeof: -5
y esto no:
#include <stdio.h> int main() { char arr[-5]; printf("content: %s; sizeof: %d\n", arr, sizeof(arr)); }con salida:
name.c:6:10: error: size of array 'arr' is negative 6 | char arr[-5]; | ^~~También esperaba un error del primer ejemplo, pero realmente no sé qué está pasando aquí.
Ninguna versión del programa se ajusta a la especificación del lenguaje C (incluso después de que los especificadores de formato se corrijan para que coincidan correctamente con el argumento size_t ). Pero los dos casos son semánticamente diferentes y violan diferentes disposiciones de la especificación del idioma.
Tomando este primero:
char arr[-5]; La expresión -5 es una expresión de constante entera, por lo que esta es una declaración de una matriz ordinaria (no una matriz de longitud variable). Está sujeto al párrafo 6.7.6.2/1 de la especificación de lenguaje C17, que dice, en parte:
Además de los calificadores de tipo opcionales y la palabra clave
static,[y]pueden delimitar una expresión o*. Si delimitan una expresión (que especifica el tamaño de un arreglo), la expresión deberá ser de tipo entero. Si la expresión es una expresión constante, tendrá un valor mayor que cero .
(Énfasis añadido.)
Eso es parte de una restricción de lenguaje, lo que significa que el compilador está obligado a emitir un mensaje de diagnóstico cuando observa una violación. En principio, no se requiere que las implementaciones rechacen el código que contiene violaciones de restricciones, pero si aceptan dichos códigos, el lenguaje no define los resultados.
Por otro lado, considere
int l = -5; char arr[l]; Debido a que l no es una expresión constante (y no lo sería incluso si l se declarara const ), la disposición discutida anteriormente no se aplica y, por separado, arr es una matriz de longitud variable. Esto está sujeto al párrafo 6.7.6.2/5 de la especificación, la parte relevante requiere de la expresión de tamaño que:
cada vez que se evalúe tendrá un valor mayor que cero
El programa viola esa disposición, pero es una regla semántica, no una restricción de lenguaje, por lo que el compilador no está obligado a diagnosticarlo y mucho menos a rechazar el código. En el caso general, el compilador no puede reconocer ni diagnosticar violaciones de esta regla particular, aunque en principio, podría hacerlo en este caso particular. Si acepta el código, el comportamiento del tiempo de ejecución no está definido.
C no establece por qué este programa emite -5 cuando lo compila y lo ejecuta con su implementación particular de C en su hardware particular. Puede que lo especifique su implementación, o puede que no. Pequeñas variaciones en el programa o diferentes versiones de su implementación C pueden producir resultados diferentes.
En general, este es otro ejemplo más de C que se niega a tomar tu mano. Los nuevos codificadores y los que están acostumbrados a interpretar lenguajes y máquinas virtuales a menudo parecen tener la expectativa de que algún componente del sistema les informará cuando hayan escrito un código incorrecto. A veces lo hace, pero otras veces simplemente hace algo con ese código incorrecto que puede o no parecerse a lo que el programador tenía en mente. La programación efectiva en C requiere atención a los detalles.