
Jabberwocky
Todos los compiladores de C que he probado no detectarán variables no inicializadas en el fragmento de código a continuación. Sin embargo, el caso es obvio aquí.
No se preocupe por la funcionalidad de este fragmento. No es un código real y lo eliminé para la investigación de este problema.
BOOL NearEqual (int tauxprecis, int max, int value)
{
int tauxtrouve; // Not initialized at this point
int totaldiff; // Not initialized at this point
for (int i = 0; i < max; i++)
{
if (2 < totaldiff) // At this point totaldiff is not initialized
{
totaldiff = 2;
tauxtrouve = value; // Commenting this line out will produce warning
}
}
return tauxtrouve == tauxprecis ; // At this point tauxtrouve is potentially
// not initialized.
}
Por otro lado, si hago un comentario tauxtrouve = value ;
obtengo el "local variable 'tauxtrouve' used without having been initialized"
advertencia.
Probé estos compiladores:
- CCG 4.9.2 con -Pared -WExtra
- Microsoft Visual C++ 2013 con todas las advertencias habilitadas

brian caín
Se exagera la obviedad con la que esta variable no se inicializa. El análisis de ruta cuesta tiempo y los proveedores de compiladores no querían implementar la función o pensaron que le costaría demasiado tiempo, o simplemente no se inscribió explícitamente.
Por ejemplo, con clang
:
$ clang -Wall -Wextra -c obvious.c
$ clang -Wall -Wextra --analyze -c obvious.c
obvious.c:9:11: warning: The right operand of '<' is a garbage value
if (2 < totaldiff) // at this point totaldiff is not initialized
^ ~~~~~~~~~
obvious.c:16:21: warning: The left operand of '==' is a garbage value
return tauxtrouve == tauxprecis ; // at this point tauxtrouve is potentially
~~~~~~~~~~ ^
2 warnings generated.
La diferencia en el tiempo de ejecución de estos ejemplos ingenuos es insignificante. Pero imagine una unidad de traducción con miles de líneas, decenas de funciones, cada una con bucles y un gran anidamiento. El número de caminos se agrava rápidamente y se convierte en una gran carga para analizar si la primera iteración a través del bucle se producirá o no antes de esa comparación.
EDITAR: @Matthieu señala que con LLVM/clang, el análisis de ruta requerido para encontrar el uso de un valor no inicializado no se agrava a medida que aumenta el anidamiento debido a la notación SSA utilizada por el IR.
No fue tan simple como “-S -emit-llvm
” como esperaba, pero encontré la salida de notación SSA que describió. Seré honesto, no estoy lo suficientemente familiarizado con LLVM IR para estar seguro, pero confío en la palabra de Matthieu.
En pocas palabras: uso clang
con --analyze
o convencer a alguien para arreglar el gcc
error.
; Function Attrs: nounwind uwtable
define i32 @NearEqual(i32 %tauxprecis, i32 %max, i32 %value) #0 {
br label %1
; <label>:1 ; preds = %7, %0
%tauxtrouve.0 = phi i32 [ undef, %0 ], [ %tauxtrouve.1, %7 ]
%i.0 = phi i32 [ 0, %0 ], [ %8, %7 ]
%2 = icmp slt i32 %i.0, %max
br i1 %2, label %3, label %9
; <label>:3 ; preds = %1
%4 = icmp slt i32 2, 2
br i1 %4, label %5, label %6
; <label>:5 ; preds = %3
br label %6
; <label>:6 ; preds = %5, %3
%tauxtrouve.1 = phi i32 [ %value, %5 ], [ %tauxtrouve.0, %3 ]
br label %7
; <label>:7 ; preds = %6
%8 = add nsw i32 %i.0, 1
br label %1
; <label>:9 ; preds = %1
%10 = icmp eq i32 %tauxtrouve.0, %tauxprecis
%11 = zext i1 %10 to i32
ret i32 %11
}

trucos
Sí, debería generar una advertencia sobre esa variable no inicializada, pero es un error de CCG. El ejemplo que se da allí es:
unsigned bmp_iter_set ();
int something (void);
void bitmap_print_value_set (void)
{
unsigned first;
for (; bmp_iter_set (); )
{
if (!first)
something ();
first = 0;
}
}
Y diagnosticado con -O2 -W -Wall
.
Desafortunadamente, ¡este año es el décimo aniversario de este error!

Nate Eldredge
Esta respuesta solo aborda GCC.
Después de una mayor investigación y comentarios, hay más cosas que en mi respuesta anterior. Este fragmento de código tiene dos variables no inicializadas y cada una de ellas no se detecta por un motivo diferente.
En primer lugar, el Documentación CCG Para el -Wuninitialized
opción dice:
Debido a que estas advertencias dependen de la optimización, las variables o elementos exactos para los que hay advertencias dependen de las opciones de optimización precisas y la versión de GCC utilizada.
Las versiones anteriores del manual de GCC redactaron esto de manera más explícita. He aquí un extracto de la manual para gcc 3.3.6:
Estas advertencias solo son posibles al optimizar la compilación, porque requieren información de flujo de datos que se calcula solo al optimizar. Si no especifica -O, simplemente no recibirá estas advertencias.
Parece que la versión actual puede dar algunas advertencias sin variables no inicializadas sin -O
pero todavía obtienes resultados mucho mejores con él.
Si compilo tu ejemplo usando gcc -std=c99 -Wall -O
Yo obtengo:
foo.c: In function ‘NearEqual’:
foo.c:15:21: warning: ‘tauxtrouve’ is used uninitialized in this function [-Wuninitialized]
return tauxtrouve == tauxprecis ; // at this point tauxtrouve is potentially
^
(Tenga en cuenta que esto es con GCC 4.8.2 ya que no tengo 4.9.x instalado, pero el principio debería ser el mismo).
Eso detecta el hecho de que tauxtrouve
no está inicializado.
Sin embargo, si reparamos parcialmente el código agregando un inicializador para tauxtrouve
(pero no para totaldiff
), luego gcc -std=c99 -Wall -O
lo acepta sin ninguna advertencia. Esto parecería ser una instancia del “error” citado en la respuesta de hacks.
Hay algunas dudas sobre si esto realmente debería considerarse un error: GCC no promete capturar todas las instancias posibles de una variable no inicializada. De hecho, no puede hacerlo con perfecta precisión, porque ese es el problema de detención. Por lo tanto, advertencias como esta pueden ser útiles cuando funcionan, ¡pero la ausencia de advertencias no prueba que su código esté libre de variables no inicializadas! Realmente no son un sustituto para verificar cuidadosamente su propio código.
En el informe de error vinculado por hackshay mucha discusión sobre si el error es reparable, o si tratar de detectar esta construcción en particular daría como resultado una tasa de falsos positivos inaceptable para otro código correcto.
Michael, no sé en qué versión de Visual Studio 2013 probaste esto, pero ciertamente está desactualizado. Actualización 4 de Visual Studio 2013 produce correctamente el siguiente mensaje de error en el primer uso de totaldiff
:
error C4700: uninitialized local variable 'totaldiff' used
Debería considerar actualizar su entorno de trabajo.
Por cierto, esto es lo que veo directamente en el editor:

No tengo idea, pero tal vez sea la optimización del compilador. Yo también estoy ansioso por saber. Espero que obtengamos la respuesta pronto.
– Sourav Ghosh
21 de noviembre de 2014 a las 14:35
¿Qué pasa si agregas el
-pedantic
bandera a gcc?– avgvstvs
21 de noviembre de 2014 a las 14:35
No estoy familiarizado con cómo se prueba la inicialización, pero echa un vistazo gcc.gnu.org/wiki/Better_Uninitialized_Warnings que encontré googleando. Especialmente
CCP assumes a value for uninitialized variables
. Si estuviera seguro de mí mismo, habría hecho este comentario y respuesta.– Pedro M.
21 de noviembre de 2014 a las 14:42
Visual Studio 2013 me dice “error C4700: variable local no inicializada ‘totaldiff’ utilizada”.
– barak manos
21 de noviembre de 2014 a las 15:07
stackoverflow.com/q/25151508/541686
– usuario541686
21 de noviembre de 2014 a las 19:08