tener - ¿Por qué no inicializado en lugar de fuera de los límites?
cuantos caracteres debe tener una meta descripcion (4)
Algunos resultados experimentales adicionales.
El uso de char b[9]
lugar de char b[]
parece hacer ninguna diferencia, gcc todavía advierte lo mismo con char b[9]
.
Curiosamente, la inicialización del elemento de una sola pasada a través del miembro "siguiente" en una struct
1) silencia la advertencia "sin inicializar" y 2) no advierte sobre el acceso fuera de la matriz.
#include <stdio.h>
typedef struct {
char c[9];
char d[9];
} TwoNines;
int main(void) {
char b[9] = { ''N'', ''i'', ''c'', ''e'', '' '', ''y'', ''o'', ''u'', ''!'' };
printf("b[] size %zu/n", sizeof b);
printf("b[9] = %d/n", b[9]); // ''b[9]'' is used uninitialized in this function [-Wuninitialized]
TwoNines e = { { ''N'', ''i'', ''c'', ''e'', '' '', ''y'', ''o'', ''u'', ''!'' }, //
{ ''N'', ''i'', ''c'', ''e'', '' '', ''y'', ''o'', ''u'', ''!'' } };
printf("e size %zu/n", sizeof e);
printf("e.c[9] = %d/n", e.c[9]); // No warning.
return 0;
}
Salida
b[] size 9
b[9] = 0
e size 18 // With 18, we know `e` is packed.
e.c[9] = 78 // ''N''
Notas:
gcc -std = c11 -O3 -g3 -pedantic -Wall -Wextra -Wconversion -c -fmessage-length = 0 -v -MMD -MP ...
gcc / gcc-7.3.0-2.i686
En el código siguiente, ¿por qué b[9]
no está inicializado en lugar de fuera de los límites?
#include <stdio.h>
int main(void)
{
char b[] = {''N'', ''i'', ''c'', ''e'', '' '', ''y'', ''o'', ''u'', ''!''};
printf("b[9] = %d/n", b[9]);
return 0;
}
Llamada del compilador:
% gcc -O2 -W -Wall -pedantic -c foo.c
foo.c: In function ‘main’:
foo.c:6:5: warning: ‘b[9]’ is used uninitialized in this function [-Wuninitialized]
printf("b[9] = %d/n", b[9]);
% gcc --version
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.6) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Actualización: ahora esto es extraño:
#include <stdio.h>
void foo(char *);
int main(void)
{
char b[] = {''N'', ''i'', ''c'', ''e'', '' '', ''y'', ''o'', ''u'', ''!''};
foo(&b[9]);
foo(&b[10]);
printf("b[9] = %d/n", b[9]);
printf("b[10] = %d/n", b[10]);
return 0;
}
La compilación de estos resultados en las advertencias que uno esperaría:
% gcc -O2 -W -Wall -pedantic -c foo.c
foo.c: In function ‘main’:
foo.c:9:5: warning: array subscript is above array bounds [-Warray-bounds]
foo(&b[10]);
^
foo.c:10:29: warning: array subscript is above array bounds [-Warray-bounds]
printf("b[9] = %d/n", b[9]);
^
foo.c:11:29: warning: array subscript is above array bounds [-Warray-bounds]
printf("b[10] = %d/n", b[10]);
De repente, gcc ve los límites de lo que es.
Creo que este podría ser el caso aquí: en el primer código, GCC advierte que no necesita la matriz char en absoluto, solo b[9]
, por lo que puede reemplazar el código con
char b_9; // = ???
printf("b[9] = %d/n", b_9);
Ahora, esta es una transformación completamente legal, porque a medida que se accedía a la matriz fuera de límites, el comportamiento es completamente indefinido . Solo en la última fase, se da cuenta de que esta variable, que es un sustituto de b[9]
, no está inicializada y emite el mensaje de diagnóstico.
¿Por qué creo esto? Porque si agrego cualquier código que haga referencia a la dirección de la matriz en la memoria , por ejemplo printf("%p/n", &b[8]);
en cualquier lugar, la matriz ahora se realiza completamente en la memoria, y el compilador diagnosticará el subíndice de la matriz por encima de los límites de la matriz .
Lo que me parece aún más interesante es que GCC no diagnostica ningún acceso fuera de los límites a menos que las optimizaciones estén habilitadas. Esto volvería a sugerir que siempre que esté escribiendo un programa nuevo, debe compilarlo con las optimizaciones habilitadas para hacer que los errores sean altamente visibles en lugar de mantenerlos ocultos con el modo de depuración;)
Cuando compila el código con -O2, la trivialidad del ejemplo hace que esta variable se optimice. Así que la advertencia es 100% correcta.
El comportamiento en la lectura b[9]
o b[10]
no está definido .
Su compilador está emitiendo una advertencia (no tiene que hacerlo), aunque el texto de advertencia es un poco engañoso, pero no es técnicamente incorrecto. En mi opinión, es bastante inteligente. ( No se requiere que el compilador de CA emita un diagnóstico para el acceso fuera de límites).
Con respecto a &b[9]
, el compilador no puede desreferenciar eso, y debe evaluarlo como b + 9
. Se le permite establecer un puntero uno más allá del final de una matriz. El comportamiento de establecer un puntero a &b[10]
no está definido .