c flowgorithm Inizializza una variabile al suo valore non definito



esercizi (4)

In C, l'inizializzazione di una variabile con il proprio valore ha senso? Se sì, per cosa?

Permettetemi di elaborare. Nelle fonti Git ci sono alcuni esempi di inizializzazione di una variabile al proprio valore non definito, come visto in transport.c o wt-status.c . Ho rimosso i compiti da quelle dichiarazioni ed eseguito test. Non vedendo regressioni, pensavo che quei compiti fossero superflui.

D'altra parte, ho fatto alcuni semplici test con GCC 4.6 e 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);
}

Compilando con -Wall -std=c99 e vari livelli -O non stampa avvisi e mostra lo status == 0 . Clang con un livello di ottimizzazione diverso da zero, tuttavia, stampa alcuni valori garbage. Mi fa inferire che i risultati di tali espressioni non sono definiti.

Posso immaginare che un simile incarico possa sopprimere un avvertimento variabile non inizializzato , ma non è il caso degli esempi presi da Git. La rimozione dei compiti non introduce alcun avviso.

Questi compiti sono un comportamento indefinito? Se no, per cosa li usi?

Ho suggerito la modifica sulla mailing list di Git. Ecco cosa ho imparato .


Answer #1

Per me l'unica ragione di tale inizializzazione autoassegnante è di evitare un avvertimento.

Nel caso del tuo transport.c , non capisco nemmeno perché sia ​​utile. Avrei lasciato cmp non inizializzato.

La mia stessa abitudine (almeno in C) è di inizializzare tutte le variabili, in genere a 0. Il compilatore ottimizzerà l'inizializzazione non necessaria e avere tutte le variabili inizializzate facilita il debugging.

C'è un caso in cui voglio che una variabile rimanga non inizializzata, e potrei auto-assegnarla: semi casuali:

 unsigned myseed = myseed;
 srand(myseed);

Answer #2

Penso che status = status non cambi il valore dello status (rispetto allo int status; ). Penso che sia usato per sopprimere l'avviso della unused variable .


Answer #3

Questo compila perché Standard C99 §6.2.1 / 7 dice:

Qualsiasi identificatore che non sia una struttura, unione o tag di enumerazione "ha uno scope che inizia subito dopo il completamento del suo dichiaratore." Il dichiaratore è seguito dall'inizializzatore.

Tuttavia, il valore dello status è Indeterminato . E non puoi fare affidamento sul fatto che sia inizializzato a qualcosa di significativo.

Come funziona?
int status crea uno spazio affinché la variabile esista nello stack (memoria locale) che viene poi letta per eseguire lo status = status , lo status potrebbe essere inizializzato su qualsiasi valore presente nello stack frame.

Come puoi difenderti da tale auto inizializzazione?
gcc fornisce un'impostazione specifica per rilevare le Inizializzazioni automatiche e segnalarle come errori:

-Werror = non inizializzato -Winit-self

Perché viene utilizzato in questo codice?
L'unico motivo per cui posso pensare che venga usato nel suddetto codice è di sopprimere l'avviso di variabile inutilizzato per ex: In transport.c , se il controllo non entra mai nel ciclo while in quel flusso di controllo cmp sarà inutilizzato e il compilatore deve generare un avviso per questo. Lo stesso scenario sembra essere con la variabile di status in wt-status.c


Answer #4

Su MacOS X 10.7.2, ho provato questo esempio - con il risultato mostrato ...

$ 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
$

Lo spazio di stack in cui lo status locale in main() è stato utilizzato da printf() modo che l'autoinizializzazione copi i dati inutili.





c