domande puntatore limitati
-
25-09-2019 - |
Domanda
Sono un po 'confuso circa le norme in materia di puntatori ristrette. Forse qualcuno là fuori mi può dare una mano.
-
E 'legale per definire puntatori ristrette annidati nel seguente modo:
int* restrict a; int* restrict b; a = malloc(sizeof(int)); // b = a; <-- assignment here is illegal, needs to happen in child block // *b = rand(); while(1) { b = a; // Is this legal? Assuming 'b' is not modified outside the while() block *b = rand(); }
-
E 'legale per ricavare un valore di puntatore ristretto come segue:
int* restrict c; int* restrict d; c = malloc(sizeof(int*)*101); d = c; for(int i = 0; i < 100; i++) { *d = i; d++; } c = d; // c is now set to the 101 element, is this legal assuming d isn't accessed? *c = rand();
Grazie! Andrew
Soluzione
Per riferimento, ecco la restrict
qualificazione piuttosto contorto definizione (da C99 6.7.3.1 "Definizione formale di limitare"):
Sia D una dichiarazione di un ordinario identificatore che fornisce un mezzo di designa un oggetto P come limitare qualificato puntatore al tipo T.
Se D appare all'interno di un blocco e non ha classe di archiviazione extern, sia B denota il blocco. Se D compare nella lista dei parametri dichiarazioni di una funzione definizione, sia B denotano la blocco associato. In caso contrario, lasciare B indicare il blocco principale (o il blocco di qualsiasi funzione è chiamata a all'avvio del programma in una freestanding ambiente).
In quanto segue, un puntatore E espressione si dice essere basata su oggetto P se (ad un certo punto sequenza nell'esecuzione di B prima valutazione E) modificare il punto P ad una copia dell'oggetto matrice in quale in precedenza sottolineato cambierebbe il valore di E. Si noti che "sulla base" è definita solo per le espressioni con tipi di puntatore.
Durante ogni esecuzione di B, sia L qualsiasi lvalue che ha & L in base ai P. Se L è utilizzato per accedere al valore della oggetto X che designa, e X è anche modificato (con qualsiasi mezzo), allora la applicare seguenti requisiti: T deve non essere const-qualificati. Ogni altro Ivalue utilizzato per accedere al valore di X deve anche avere il suo indirizzo sulla base di accesso P. Ogni modifica che dovrà X essere considerato anche di modificare P, per Ai fini del presente sottoclausola. Se P è assegnato il valore di un puntatore E espressione che si basa su un'altra ristretto oggetto P2 puntatore, associato con il blocco B2, allora o l'esecuzione di B2 inizia prima l'esecuzione di B, o esecuzione di B2 termina prima L'incarico. Se questi requisiti non sono soddisfatti, allora il comportamento non è definito.
Qui un'esecuzione di mezzi che B porzione dell'esecuzione del programma che corrisponderebbe alla vita di un oggetto con tipo scalare e durata memorizzazione automatica associato a B.
La mia lettura dei mezzi di cui sopra che nella vostra prima domanda, a
non può essere assegnato a b
, anche all'interno di un blocco "figlio" - il risultato è indefinito. una tale cessione potrebbe essere effettuata se b
fosse dichiarato dal fatto che 'sottoblocco', ma poiché b
è dichiarato al stessa portata a
, l'assegnazione non può essere effettuato.
Per la domanda 2, le assegnazioni tra c
e d
risultato anche nel comportamento non definito (in entrambi i casi).
Il bit rilevante dallo standard (per entrambe le domande) è:
Se P viene assegnato il valore di un puntatore espressione E che si basa sulla altro P2 puntatore di oggetto limitato, associato con il blocco B2, allora o l'esecuzione di B2 inizia prima l'esecuzione di B, o esecuzione di B2 termina prima l'assegnazione.
Poiché i puntatori ristrette sono associati allo stesso blocco, non è possibile per il blocco B2 iniziare prima dell'esecuzione di B, o B2 per terminare prima della cessione (dal B e B2 sono stesso blocco).
La norma fornisce un esempio che rende questo abbastanza chiaro (credo - la chiarezza di 4 brevi paragrafi della definizione di restrict
è alla pari con C ++ 's regole di risoluzione dei nomi):
Esempio 4:
La regola che limita le assegnazioni tra puntatori limitate non lo fa distinguere tra una chiamata di funzione ed un blocco annidato equivalente. Con una sola eccezione, solo "esterno a interno" assegnazioni tra puntatori restrizioni dichiarate in nidificato blocchi hanno definito il comportamento.
{ int * restrict p1; int * restrict q1; p1 = q1; // undefined behavior { int * restrict p2 = p1; // valid int * restrict q2 = q1; // valid p1 = q2; // undefined behavior p2 = q2; // undefined behavior } }
Altri suggerimenti
Il qualificatore tipo restrict
è un indicazione al compilatore che, se la memoria indirizzata dal puntatore restrict
qualificato viene modificato, nessun altro puntatore accederanno stessa memoria. Il compilatore può scegliere di ottimizzare il codice che coinvolgono puntatori restrict
qualificato in un modo che altrimenti potrebbero portare a comportamenti scorretti. E 'responsabilità del programmatore per garantire che limitare qualificati vengono utilizzati puntatori come sono stati destinati ad essere utilizzati. In caso contrario, un comportamento indefinito può comportare. ( link )
Come si può vedere dalla descrizione di cui sopra, sia le assegnazioni sono illegali, che può funzionare in eseguibili prodotte da alcuni compilatori, ma rompere in altri. Non aspettatevi il compilatore stesso ad emettere errori o avvisi come restrict
dà solo la possibilità di eseguire l'ottimizzazione certo, che si può scegliere di non eseguire, come nel caso di volatile
.