Perché questo per il loop esce su alcune piattaforme e non su altre?


240

Di recente ho iniziato a studiare C e sto prendendo una lezione con C come materia. Attualmente sto giocando con i loop e sto incontrando un comportamento strano che non so come spiegare.

#include <stdio.h>

int main()
{
  int array[10],i;

  for (i = 0; i <=10 ; i++)
  {
    array[i]=0; /*code should never terminate*/
    printf("test \n");

  }
  printf("%d \n", sizeof(array)/sizeof(int));
  return 0;
}

Sul mio laptop con Ubuntu 14.04, questo codice non si interrompe. Funziona fino al completamento. Sul computer della mia scuola con CentOS 6.6 funziona anche bene. Su Windows 8.1, il ciclo non termina mai.

La cosa ancora più strana è che quando modifico le condizioni del forloop in:, i <= 11il codice termina solo sul mio laptop con Ubuntu. Non termina mai in CentOS e Windows.

Qualcuno può spiegare cosa sta succedendo nella memoria e perché i diversi sistemi operativi che eseguono lo stesso codice danno risultati diversi?

EDIT: so che il ciclo for va oltre i limiti. Lo sto facendo intenzionalmente. Non riesco proprio a capire come il comportamento possa essere diverso tra diversi sistemi operativi e computer.


147
Poiché si sta eseguendo il superamento dell'array, si verifica un comportamento indefinito. Comportamento indefinito significa che può succedere di tutto, anche se sembra funzionare. Pertanto, "il codice non deve mai terminare" non è un'aspettativa valida.
Kaylum,

37
Esatto, benvenuto in C. Il tuo array ha 10 elementi - numerati da 0 a 9.
Yetti99

14
@JonCav Hai infranto il codice. Stai ottenendo un comportamento indefinito che è un codice non funzionante.
Kaylum,

50
Bene, il punto è che il comportamento indefinito è esattamente questo. Non è possibile testarlo in modo affidabile e dimostrare che accadrà qualcosa di definito. Quello che probabilmente sta succedendo nel tuo computer Windows è che la variabile iè memorizzata subito dopo la fine arraye la stai sovrascrivendo array[10]=0;. Questo potrebbe non essere il caso di una build ottimizzata sulla stessa piattaforma, che può essere archiviata iin un registro e non riferirsi mai ad esso in memoria.
Paddy,

46
Perché la non prevedibilità è una proprietà fondamentale del comportamento indefinito. Devi capirlo ... Assolutamente tutte le scommesse sono spente.
Paddy,

Risposte:


356

Sul mio laptop con Ubuntu 14.04, questo codice non si interrompe e viene eseguito fino al completamento. Sul computer della mia scuola con CentOS 6.6 funziona anche bene. Su Windows 8.1, il ciclo non termina mai.

La cosa più strana è quando modifico il condizionale del forloop in:, i <= 11il codice termina solo sul mio laptop con Ubuntu. CentOS e Windows non terminano mai.

Hai appena scoperto che la memoria calpesta. Puoi leggere di più qui: Cos'è uno "stomp di memoria"?

Quando si alloca int array[10],i;, quelle variabili vanno in memoria (in particolare, sono allocate nello stack, che è un blocco di memoria associato alla funzione). array[]e iprobabilmente sono adiacenti l'uno all'altro in memoria. Sembra che su Windows 8.1, isi trovi in array[10]. Su CentOS, isi trova in array[11]. E su Ubuntu, non è in nessun punto (forse è array[-1]?).

Prova ad aggiungere queste istruzioni di debug al tuo codice. Si dovrebbe notare che sull'iterazione 10 o 11, array[i]punti a i.

#include <stdio.h>
 
int main() 
{ 
  int array[10],i; 
 
  printf ("array: %p, &i: %p\n", array, &i); 
  printf ("i is offset %d from array\n", &i - array);

  for (i = 0; i <=11 ; i++) 
  { 
    printf ("%d: Writing 0 to address %p\n", i, &array[i]); 
    array[i]=0; /*code should never terminate*/ 
  } 
  return 0; 
} 

6
Ehi grazie! Questo ha davvero spiegato un bel po '. In Windows afferma che se offset 10 dall'array, mentre in CentOS e Ubuntu è -1. La cosa più strana è se commento il tuo codice di debugger, CentOS non può eseguire il codice (si blocca), ma con il tuo codice di debug viene eseguito. C sembra essere un linguaggio molto finora X_x
JonCav il

12
@JonCav "si blocca" può accadere se scrivere per array[10]distruggere il frame dello stack, per esempio. Come può esserci una differenza tra il codice con o senza l'output di debug? Se l'indirizzo di inon è mai necessario, il compilatore potrebbe ottimizzare i. in un registro, cambiando così il layout di memoria nello stack ...
Hagen von Eitzen,

2
Non penso che sia in sospeso, penso che sia in un ciclo infinito perché sta ricaricando il contatore del ciclo dalla memoria (che è appena stato azzerato array[10]=0. Se hai compilato il codice con l'ottimizzazione attiva, probabilmente non accadrà. (Perché C ha regole di aliasing che limitano i tipi di accesso alla memoria che devono essere considerati potenzialmente sovrapposti ad altra memoria. Come variabile locale di cui non si prende mai l'indirizzo, penso che un compilatore dovrebbe essere in grado di assumere che nulla lo alias. Comunque, cancellando la fine di un array è un comportamento indefinito. Cerca sempre di evitare, a seconda di ciò.
Peter Cordes,

4
Un'altra alternativa è che un compilatore di ottimizzazione rimuove completamente l'array, poiché non ha alcun effetto osservabile (nel codice originale della domanda). Quindi, il codice risultante potrebbe semplicemente stampare quella stringa costante undici volte, seguita dalla stampa della dimensione costante e rendere così inosservabile l'overflow.
Holger,

9
@JonCav Direi in generale che non devi sapere di più sulla gestione della memoria e invece semplicemente sapere di non scrivere codice indefinito, in particolare, non scrivere oltre la fine di un array ...
T. Kiley

98

Il bug si trova tra questi pezzi di codice:

int array[10],i;

for (i = 0; i <=10 ; i++)

array[i]=0;

Poiché arrayha solo 10 elementi, nell'ultima iterazione array[10] = 0;c'è un buffer overflow. Gli overflow del buffer sono COMPORTAMENTI INDISPENSABILI , il che significa che potrebbero formattare il disco rigido o causare la fuga dei demoni dal naso.

È abbastanza comune che tutte le variabili dello stack siano disposte l'una accanto all'altra. Se isi trova dove array[10]scrive, allora l'UB si reimposterà isu 0, portando così al ciclo non terminato.

Per risolvere, cambia la condizione del loop in i < 10.


6
Nitpick: in realtà non è possibile formattare il disco rigido su qualsiasi sistema operativo sano sul mercato a meno che non si stia eseguendo come root (o equivalente).
Kevin,

26
@Kevin quando invochi UB, rinunci a qualsiasi pretesa di sanità mentale.
o11c,

7
Non importa se il tuo codice è sano. Il sistema operativo non ti consente di farlo.
Kevin,

2
@Kevin L'esempio con la formattazione del disco rigido è nato molto prima. Anche gli unixes del tempo (dove ha avuto origine la C) erano abbastanza felici nel permetterti di fare cose del genere - e anche oggi, molte distro ti permetteranno felicemente di iniziare a cancellare tutto con rm -rf /anche quando non sei root, non "formattando" l'intero disco ovviamente, ma distruggendo comunque tutti i tuoi dati. Ahia.
Luaan,

5
@Kevin, ma un comportamento indefinito può sfruttare una vulnerabilità del sistema operativo e quindi elevarsi per installare un nuovo driver del disco rigido e quindi iniziare a pulire l'unità.
maniaco del cricchetto,

38

In quella che dovrebbe essere l'ultima esecuzione del ciclo, scrivi array[10], ma ci sono solo 10 elementi nell'array, numerati da 0 a 9. La specifica del linguaggio C dice che si tratta di "comportamento indefinito". Ciò significa in pratica che il tuo programma tenterà di scrivere sul intpezzo di memoria di grandi dimensioni che si trova immediatamente dopo arraynella memoria. Ciò che accade dipende da ciò che, in effetti, si trova lì, e questo dipende non solo dal sistema operativo, ma anche dal compilatore, dalle opzioni del compilatore (come le impostazioni di ottimizzazione), dall'architettura del processore, dal codice circostante , ecc. Potrebbe anche variare da un'esecuzione all'altra, ad esempio a causa della randomizzazione dello spazio degli indirizzi (probabilmente non su questo esempio di giocattolo, ma accade nella vita reale). Alcune possibilità includono:

  • La posizione non è stata utilizzata. Il loop termina normalmente.
  • La posizione è stata usata per qualcosa che aveva il valore 0. Il ciclo termina normalmente.
  • La posizione conteneva l'indirizzo di ritorno della funzione. Il ciclo termina normalmente, ma il programma si arresta in modo anomalo perché tenta di passare all'indirizzo 0.
  • La posizione contiene la variabile i. Il ciclo non termina mai perché si iriavvia su 0.
  • La posizione contiene qualche altra variabile. Il ciclo termina normalmente, ma poi accadono cose "interessanti".
  • La posizione è un indirizzo di memoria non valido, ad es. Perché si arraytrova alla fine di una pagina di memoria virtuale e la pagina successiva non è mappata.
  • I demoni volano fuori dal tuo naso . Fortunatamente alla maggior parte dei computer manca l'hardware necessario.

Quello che hai osservato su Windows è che il compilatore ha deciso di posizionare la variabile iimmediatamente dopo l'array in memoria, quindi ha array[10] = 0finito per assegnare a i. Su Ubuntu e CentOS, il compilatore non è stato inserito ilì. Quasi tutte le implementazioni C raggruppano le variabili locali in memoria, su uno stack di memoria , con una grande eccezione: alcune variabili locali possono essere inserite interamente nei registri . Anche se la variabile è nello stack, l'ordine delle variabili è determinato dal compilatore e può dipendere non solo dall'ordine nel file di origine ma anche dai loro tipi (per evitare di sprecare memoria per vincoli di allineamento che lascerebbero buchi) , sui loro nomi, su alcuni valori di hash utilizzati nella struttura dati interna di un compilatore, ecc.

Se vuoi scoprire cosa ha deciso di fare il tuo compilatore, puoi dirlo per mostrarti il ​​codice dell'assemblatore. Oh, e impara a decifrare l'assemblatore (è più facile che scriverlo). Con GCC (e alcuni altri compilatori, specialmente nel mondo Unix), passa l'opzione -Sper produrre il codice assembler anziché un binario. Ad esempio, ecco lo snippet dell'assemblatore per il loop dalla compilazione con GCC su amd64 con l'opzione di ottimizzazione -O0(nessuna ottimizzazione), con i commenti aggiunti manualmente:

.L3:
    movl    -52(%rbp), %eax           ; load i to register eax
    cltq
    movl    $0, -48(%rbp,%rax,4)      ; set array[i] to 0
    movl    $.LC0, %edi
    call    puts                      ; printf of a constant string was optimized to puts
    addl    $1, -52(%rbp)             ; add 1 to i
.L2:
    cmpl    $10, -52(%rbp)            ; compare i to 10
    jle     .L3

Qui la variabile iè di 52 byte sotto la parte superiore dello stack, mentre l'array inizia 48 byte sotto la parte superiore dello stack. Quindi questo compilatore sembra essere stato posizionato ipoco prima dell'array; sovrascriveresti ise ti capitasse di scrivere array[-1]. Se cambi array[i]=0a array[9-i]=0, otterrai un loop infinito su questa particolare piattaforma con queste particolari opzioni del compilatore.

Ora compiliamo il tuo programma con gcc -O1.

    movl    $11, %ebx
.L3:
    movl    $.LC0, %edi
    call    puts
    subl    $1, %ebx
    jne     .L3

È più corto! Il compilatore non ha solo rifiutato di allocare una posizione dello stack per i- è sempre e solo memorizzato nel registro ebx- ma non si è preoccupato di allocare memoria arrayo di generare codice per impostare i suoi elementi, perché ha notato che nessuno degli elementi sono mai usati.

Per rendere più chiaro questo esempio, assicuriamoci che le assegnazioni di array vengano eseguite fornendo al compilatore qualcosa che non è in grado di ottimizzare. Un modo semplice per farlo è usare l'array da un altro file - a causa della compilazione separata, il compilatore non sa cosa succede in un altro file (a meno che non ottimizzi al momento del collegamento, che gcc -O0o gcc -O1no). Crea un file sorgente use_array.ccontenente

void use_array(int *array) {}

e cambia il tuo codice sorgente in

#include <stdio.h>
void use_array(int *array);

int main()
{
  int array[10],i;

  for (i = 0; i <=10 ; i++)
  {
    array[i]=0; /*code should never terminate*/
    printf("test \n");

  }
  printf("%zd \n", sizeof(array)/sizeof(int));
  use_array(array);
  return 0;
}

Compila con

gcc -c use_array.c
gcc -O1 -S -o with_use_array1.c with_use_array.c use_array.o

Questa volta il codice dell'assemblatore è simile al seguente:

    movq    %rsp, %rbx
    leaq    44(%rsp), %rbp
.L3:
    movl    $0, (%rbx)
    movl    $.LC0, %edi
    call    puts
    addq    $4, %rbx
    cmpq    %rbp, %rbx
    jne     .L3

Ora l'array è nello stack, 44 byte dall'alto. Che dire i? Non appare da nessuna parte! Ma il contatore di loop viene mantenuto nel registro rbx. Non è esattamente i, ma l'indirizzo del array[i]. Il compilatore ha deciso che dal momento che il valore di inon è mai stato usato direttamente, non ha senso eseguire l'aritmetica per calcolare dove memorizzare 0 durante ogni esecuzione del ciclo. Invece quell'indirizzo è la variabile del ciclo e l'aritmetica per determinare i confini è stata eseguita in parte in fase di compilazione (moltiplicare 11 iterazioni per 4 byte per elemento dell'array per ottenere 44) e in parte in fase di esecuzione ma una volta per tutte prima dell'inizio del ciclo ( eseguire una sottrazione per ottenere il valore iniziale).

Anche su questo esempio molto semplice, abbiamo visto come cambiare le opzioni del compilatore (attivare l'ottimizzazione) o cambiare qualcosa di minore ( array[i]in array[9-i]) o persino cambiare qualcosa apparentemente non correlato (aggiungendo la chiamata a use_array) può fare una differenza significativa rispetto a ciò che il programma eseguibile ha generato dal compilatore fa. Le ottimizzazioni del compilatore possono fare molte cose che potrebbero apparire non intuitive sui programmi che invocano comportamenti indefiniti . Ecco perché il comportamento indefinito viene lasciato completamente indefinito. Quando ti allontani leggermente dalle tracce, nei programmi del mondo reale, può essere molto difficile capire la relazione tra ciò che fa il codice e ciò che avrebbe dovuto fare, anche per programmatori esperti.


25

A differenza di Java, C non esegue il controllo dei limiti dell'array, ovvero non esiste ArrayIndexOutOfBoundsException, il compito di assicurarsi che l'indice dell'array sia valido viene lasciato al programmatore. Fare questo di proposito porta a comportamenti indefiniti, tutto può succedere.


Per un array:

int array[10]

gli indici sono validi solo nell'intervallo 0a 9. Tuttavia, stai cercando di:

for (i = 0; i <=10 ; i++)

accedi array[10]qui, cambia la condizione ini < 10


6
Farlo non di proposito porta anche a comportamenti indefiniti - il compilatore non può dirlo! ;-)
Toby Speight,

1
Usa una macro per trasmettere i tuoi errori come avvertenze: #define UNINTENDED_MISTAKE (EXP) printf ("Avvertenza: errore" #EXP "\ n");
Lkraider,

1
Voglio dire, se stai commettendo un errore di proposito, potresti anche identificarlo come tale e renderlo sicuro per evitare il comportamento indefinito; D
Lkraider,

19

Hai una violazione dei limiti e, sulle piattaforme non terminanti, credo che tu stia inavvertitamente impostando ilo zero alla fine del ciclo, in modo che ricomincia da capo.

array[10]è invalido; contiene 10 elementi, array[0]attraverso array[9], ed array[10]è l'undicesimo. Il ciclo dovrebbe essere scritto per interrompere prima 10 , come segue:

for (i = 0; i < 10; i++)

Laddove le array[10]terre sono definite dall'implementazione e, in modo divertente, su due delle tue piattaforme, finiscono sulle iquali apparentemente queste piattaforme sono disposte direttamente dopo array. iè impostato su zero e il ciclo continua per sempre. Per le altre tue piattaforme, ipotrebbe trovarsi prima arrayo arraydopo avere qualche imbottitura.


Non credo che valgrind possa prenderlo perché è ancora una posizione valida, ma ASAN può farlo.
o11c,

13

Dichiarate int array[10]significa che arrayha indice 0a 9( 10elementi interi totali che può contenere). Ma il ciclo seguente,

for (i = 0; i <=10 ; i++)

ciclo 0per 10significa 11tempo. Quindi, quando i = 10si riempirà il buffer e causerà un comportamento indefinito .

Quindi prova questo:

for (i = 0; i < 10 ; i++)

o,

for (i = 0; i <= 9 ; i++)

7

È indefinito in array[10]e dà un comportamento indefinito come descritto in precedenza. Pensala in questo modo:

Ho 10 articoli nel mio carrello della spesa. Loro sono:

0: Una scatola di cereali
1: Pane
2: Latte
3: Torta
4: Uova
5: Torta
6: A 2 litri di soda
7: Insalata
8: Hamburger
9: Gelato

cart[10]è indefinito e può dare un'eccezione fuori limite in alcuni compilatori. Ma a quanto pare non è così. L'undicesimo articolo apparente è un articolo che non si trova nel carrello. L'undicesimo oggetto punta a quello che chiamerò un "oggetto poltergeist". Non è mai esistito, ma era lì.

Perché alcuni compilatori danno iun indice di array[10]o di array[11]o addirittura array[-1]è a causa della sua dichiarazione di inizializzazione / dichiarazione. Alcuni compilatori interpretano questo come:

  • "Assegna 10 blocchi di ints per array[10]un altro intblocco. Per renderlo più semplice, mettili uno accanto all'altro."
  • Come prima, ma spostalo di uno o due spazi di distanza, in modo che array[10]non indichi i.
  • Fare lo stesso di prima, ma allocare iat array[-1](perché un indice di un array non può, o non dovrebbe essere negativo), oppure allocarlo in un punto completamente diverso perché il sistema operativo può gestirlo ed è più sicuro.

Alcuni compilatori vogliono che le cose vadano più veloci e altri preferiscono la sicurezza. Riguarda il contesto. Se stavo sviluppando un'app per l'antico sistema operativo BREW (il sistema operativo di un telefono di base), ad esempio, non mi interesserebbe la sicurezza. Se stavo sviluppando per un iPhone 6, allora potrebbe funzionare velocemente, qualunque cosa accada, quindi avrei bisogno di un'enfasi sulla sicurezza. (Seriamente, hai letto le Linee guida dell'App Store di Apple o hai letto sullo sviluppo di Swift e Swift 2.0?)


Nota: ho digitato l'elenco in modo che diventi "0, 1, 2, 3, 4, 5, 6, 7, 8, 9", ma il linguaggio Markup di SO ha corretto le posizioni del mio elenco ordinato.
DDPWNAGE

6

Poiché hai creato un array di dimensioni 10, per la condizione del ciclo dovrebbe essere la seguente:

int array[10],i;

for (i = 0; i <10 ; i++)
{

Attualmente si sta tentando di accedere alla posizione non assegnata dalla memoria utilizzando array[10]e sta causando il comportamento indefinito . Comportamento indefinito significa che il tuo programma si comporterà in modo indeterminato, quindi può dare risultati diversi in ogni esecuzione.


5

Bene, il compilatore C tradizionalmente non controlla i limiti. È possibile ottenere un errore di segmentazione nel caso in cui ci si riferisca a una posizione che non "appartiene" al proprio processo. Tuttavia, le variabili locali sono allocate nello stack e, a seconda del modo in cui è allocata la memoria, l'area appena oltre l'array ( array[10]) può appartenere al segmento di memoria del processo. Pertanto, non viene generata alcuna trappola per errori di segmentazione ed è quello che sembra provare. Come altri hanno sottolineato, questo è un comportamento indefinito in C e il tuo codice può essere considerato irregolare. Dato che stai imparando C, è meglio prendere l'abitudine di verificare i limiti nel codice.


4

Oltre alla possibilità che la memoria possa essere disposta in modo tale che un tentativo di scrivere su a[10]sovrascrive effettivamente i, sarebbe anche possibile che un compilatore di ottimizzazione possa determinare che il test del ciclo non può essere raggiunto con un valore imaggiore di dieci senza che il codice abbia prima accesso al elemento array inesistente a[10].

Dal momento che un tentativo di accedere a quell'elemento sarebbe un comportamento indefinito, il compilatore non avrebbe alcun obbligo riguardo a ciò che il programma potrebbe fare dopo quel punto. Più in particolare, poiché il compilatore non avrebbe l'obbligo di generare codice per controllare l'indice del loop in ogni caso in cui potrebbe essere maggiore di dieci, non avrebbe l'obbligo di generare codice per verificarlo affatto; si potrebbe invece supporre che il <=10test fornirà sempre vero. Si noti che ciò sarebbe vero anche se il codice leggesse a[10]anziché scriverlo.


3

Quando si passa in rassegna i==9si assegna zero agli "elementi dell'array" che si trovano effettivamente oltre l'array , quindi si sovrascrive alcuni altri dati. Molto probabilmente si sovrascrive la ivariabile, che si trova dopo a[]. In questo modo è sufficiente reimpostare la ivariabile su zero e quindi riavviare il ciclo.

Potresti scoprirlo tu stesso se stampassi inel ciclo:

      printf("test i=%d\n", i);

invece di solo

      printf("test \n");

Naturalmente questo risultato dipende fortemente dall'allocazione di memoria per le variabili, che a sua volta dipende da un compilatore e dalle sue impostazioni, quindi è generalmente un comportamento indefinito - ecco perché i risultati su macchine diverse o sistemi operativi diversi o su compilatori diversi possono differire.


0

l'errore è nella porzione array [10] w / c è anche l'indirizzo di i (int array [10], i;). quando l'array [10] è impostato su 0, allora l'i sarebbe 0 w / c resetta l'intero loop e causa il loop infinito. ci sarà un ciclo infinito se l'array [10] è compreso tra 0-10. il loop corretto dovrebbe essere per (i = 0; i <10; i ++) {...} int array [10], i; per (i = 0; i <= 10; i ++) array [i] = 0;


0

Suggerirò qualcosa che non trovo sopra:

Prova ad assegnare l'array [i] = 20;

Immagino che questo dovrebbe terminare il codice ovunque .. (dato che tieni i <= 10 o ll)

Se questo funziona, puoi decidere con fermezza che le risposte qui specificate sono già corrette [la risposta relativa alla memoria calpesta una per es.]


-9

Ci sono due cose che non vanno qui. L'int i è in realtà un elemento array, array [10], come visto nello stack. Poiché hai consentito all'indicizzazione di creare effettivamente array [10] = 0, l'indice del ciclo, i, non supererà mai 10. Crealo for(i=0; i<10; i+=1).

i ++ è, come lo chiamerebbe K&R , "cattivo stile". Aumenta i della dimensione di i, non 1. i ++ è per la matematica del puntatore e i + = 1 è per l'algebra. Sebbene ciò dipenda dal compilatore, non è una buona convenzione per la portabilità.


5
-1 Completamente sbagliato. La variabile iNON è un elemento dell'array a[10], non c'è alcun obbligo o suggerimento per un compilatore di metterlo nello stack immediatamente dopo a[] : può anche essere posizionato prima dell'array o separato con un po 'di spazio aggiuntivo. Potrebbe anche essere allocato al di fuori della memoria principale, ad esempio in un registro CPU. È anche falso ++per i puntatori e non per i numeri interi. Completamente sbagliato è 'i ++ sta incrementando i della dimensione di i' - leggi la descrizione dell'operatore nella definizione della lingua!
CiaPan,

ecco perché funziona su alcune piattaforme e non su altre. è l'unica spiegazione logica del perché si avvolge per sempre su Windows. per quanto riguarda I ++, non è un numero intero di puntatori. leggi le Scritture ... il "linguaggio di programmazione C". di Kernigan e Ritche, se vuoi ho una copia autografata, e programmo in c dal 1981.
SkipBerne

1
Leggi il codice sorgente di OP e trova la dichiarazione della variabile i- è di inttipo. È un numero intero , non un puntatore; un numero intero, usato come indice del array,.
CiaPan,

1
L'ho fatto ed è per questo che ho commentato come ho fatto. forse dovresti capire che a meno che il compilatore non includa i controlli dello stack e in questo caso non importerebbe come riferimento dello stack quando I = 10 farebbe effettivamente riferimento, in alcune compilazioni, all'indice dell'array e che rientra nei limiti della regione dello stack. i compilatori non possono risolvere stupidi. le compilazioni potrebbero fare una correzione come sembra, ma una pura interpretazione del linguaggio di programmazione c non supporterebbe questa convenzione e come detto dall'OP darebbe risultati non portabili.
SkipBerne

@SkipBerne: considera di eliminare la tua risposta prima di essere "premiato" con più punti negativi.
Peter VARGA,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.