Domanda

Sono un po 'confuso circa le norme in materia di puntatori ristrette. Forse qualcuno là fuori mi può dare una mano.

  1. 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();
    }
    
  2. 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

È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top