2011-11-27 14 views
20

En C, ¿tiene sentido inicializar una variable a su propio valor? Si es así, ¿para qué?Inicializar una variable en su propio valor indefinido

Déjenme elaborar. En las fuentes de Git, hay algunos ejemplos de inicialización de una variable a su propio valor indefinido, como se ve en transport.c o wt-status.c. Eliminé las asignaciones de esas declaraciones y realicé pruebas. Al no ver regresiones, pensé que esas asignaciones eran redundantes.

Por otro lado, hice algunas pruebas simples con GCC 4.6 y Clang 2.9.

#include <stdio.h> 
int main() { 
    printf("print to increase probability of registers being non-zero\n"); 
    int status = status; 
    return printf("%i\n", status); 
} 

Compilar con -Wall -std=c99 y varios niveles -O imprime ninguna advertencia y muestra que status == 0. Clang con un nivel de optimización distinto de cero imprime algunos valores de basura. Me hace inferir que los resultados de tales expresiones no están definidos.

Me imagino que dicha asignación puede suprimir una advertencia de variable no inicializada, pero no es el caso de los ejemplos tomados de Git. Eliminar asignaciones no introduce ninguna advertencia.

¿Son estas asignaciones un comportamiento indefinido? Si no, ¿para qué los usas?


He sugerido el cambio en la lista de correo de Git. Here's what I've learned.

+0

Tal vez los ejemplos en git no supriman una advertencia de variable no inicializada para * su * sistema, pero en sistemas que otros desarrolladores utilizan regularmente. Con GCC, las advertencias de variables no inicializadas se ven afectadas por indicadores de optimización, y Clang produce un conjunto de advertencias bastante diferente, aunque es un "reemplazo directo" para GCC. –

+1

Inicializaría tales variables a 0 (o -1) en lugar de descartar la inicialización por completo. Alguien agregó el código para un propósito; Puedo respetar el propósito aunque encuentre extraño el mecanismo. –

+1

@JonathanLeffler, no solo es extraño, en plataformas con representaciones de trampa esto produce un comportamiento indefinido. –

Respuesta

11

Esto compila porque estándar C99 §6.2.1/7 dice:

Cualquier identificador que no es una estructura, unión o enumeración etiqueta "tiene un alcance que comienza justo después de la finalización de su declarador " El declarador es seguido por el inicializador.

Sin embargo, el valor de status es indeterminado. Y no puede confiar en que se inicialice a algo significativo.

¿Cómo funciona?
int status crea un espacio para que exista la variable en la pila (almacenamiento local) que luego se lee para realizar status = status, status puede inicializarse a cualquier valor que estuviera presente en el marco de la pila.

¿Cómo se puede evitar esa autoinicialización?
gcc proporciona un ajuste específico para detectar e informar Inicializaciones auto como errores:

-Werror = sin inicializar -Winit-auto

por qué se utiliza en este código?
La única razón por la que creo que se está utilizando en dicho código es suprimir la advertencia de la variable no utilizada por ejemplo: en transport.c, si el control nunca entra dentro del while, el flujo de control cmp no se utilizará y el el compilador debe estar generando una advertencia para ello. El mismo escenario parece estar con status variable en wt-status.c

+2

Creo que la idea no es suprimir la advertencia 'variable no utilizada' (puede hacerlo más simplemente eliminando la variable no utilizada), sino la advertencia '(a veces) utilizada antes de inicializar'. Es un detalle menor: no altera la validez de la parte principal de su respuesta. –

+0

@JonathanLeffler: Tu comentario es perfecto. Me equivoqué en mi respuesta. –

1

Para mí, la única razón de tal inicialización autoasignable es evitar una advertencia.

En el caso de su transport.c, ni siquiera entiendo por qué es útil. Hubiera dejado cmp sin inicializar.

Mi propio hábito (al menos en C) es inicializar todas las variables, generalmente a 0. El compilador optimizará la inicialización innecesaria, y tener todas las variables inicializadas facilita la depuración.

hay un caso cuando quiero una variable permanezca sin inicializar, y yo podría auto-asignarlo: semillas aleatorias:

unsigned myseed = myseed; 
srand(myseed); 
+0

¿Pero hay herramientas de análisis en tiempo de ejecución que notarían que 'cmp' se lee cuando aún contiene bytes no inicializados? La lógica debe obligar a 'cmp' a asignar algo en el' while' antes de que se lea en 'if', así que quieres que el compilador" se calle porque el humano sabe lo que está haciendo ", pero' int cmp = 0' haría vencer el análisis de tiempo de ejecución y posiblemente ocultar un error. –

+0

¿Quiere decir * análisis en tiempo de compilación * no * de tiempo de ejecución *? Pero no entiendo tu comentario. –

+0

'int cmp = cmp' podría ser suficiente para engañar al compilador haciéndole creer que' cmp' siempre se asigna antes de ser leído para que las advertencias en tiempo de compilación sean suprimidas. Pero, si observa los bytes en tiempo de ejecución, 'int cmp = cmp' todavía deja' cmp' lleno de basura hasta que la condición del bucle 'while' lo inicializa; entonces, si la lógica es defectuosa y el 'si' puede leer' cmp' sin que el 'while' le asigne un valor, entonces eso podría detectarse cuando se usa' int cmp = cmp'. Usar 'int cmp = 0' suprimiría ambas advertencias posibles. –

1

en MacOS X 10.7.2, probé este ejemplo - con el resultado se muestra ...

$ cat x3.c 
#include <stdio.h> 

int status = -7; 

int main() 
{ 
    printf("status = %d\n", status); 
    int status = status; 
    printf("status = %d\n", status); 
    return 0; 
} 
$ make x3 
gcc -O -std=c99 -Wall -Wextra x3.c -o x3 
$ ./x3 
status = -7 
status = 1787486824 
$ 

el espacio de pila donde el status local en main() ha sido utilizado por lo que el printf() copias auto-inicialización de basura alrededor.

0

Creo status = status no cambia el valor de status (en comparación con int status;). Creo que se usa para suprimir la advertencia unused variable.

Cuestiones relacionadas