Domanda

Supponiamo di avere grande array che a calcolare un indice in e passare ad una seconda funzione. Come semplice esempio, qualcosa come:

void foo(float* array, float c, unsigned int n)
{
    for (unsigned int i = 0; i < n; ++i)
        array[i] *= c;
}

void bar(float* restrict array, float* restrict array2, unsigned int m, unsigned int n)
{
    for (unsigned int i = 0; i < m; ++i)
        foo(&array[i * n], array2[i], n);
}

E 'questo infrange le regole per limitare in bar (), dove si passa l'indirizzo della parte della matrice di foo (), anche se non si utilizza mai veramente l'alias per una parte della matrice all'interno bar ()?

È stato utile?

Soluzione

(Tutte le citazioni si riferiscono a N1256 , che è più C99 rettifiche tecnica (TC3).)

La definizione formale di restrict è dato in §6.7.3.1. Cito il più importante sottoclausola di seguito. P è un puntatore restrict qualificato per tipo T cui portata è un B blocco. Un E espressione puntatore è detto essere basato su P se dipende dal valore di P sé, non il valore che punti P a.

  

Durante ogni esecuzione di B, lascia L essere qualsiasi Ivalue che ha &L basato su P. Se L viene utilizzato per accedere al valore della X oggetto che designa, e X è anche modificato (con qualsiasi mezzo), allora la applicano seguenti requisiti:

     
      
  • T non sarà const-qualificato.
  •   
  • Ogni altro valore assegnabile utilizzato per accedere al valore della X deve anche avere il suo indirizzo in base a P.
  •   
  • Ogni accesso che modifica X si considera anche di modificare P, ai fini del presente sottoclausola.
  •   
  • Se P viene assegnato il valore di un E espressione puntatore che si basa su un altro P2 puntatore di oggetto ristretta, associato blocco B2, allora o l'esecuzione di B2 inizia prima dell'esecuzione di B, o l'esecuzione di B2 termina prima della cessione.
  •   
     

Se questi requisiti non sono soddisfatti, quindi il comportamento è indefinito.


Diamo un'occhiata a ciò che le regole hanno da dire su accessi a parti del bar di array in foo. Si comincia con array, un puntatore limitare qualificato dichiarato nella lista dei parametri di bar. Per chiarezza, io alfa-convertire i parametri di foo:

void foo(float* b, float c, unsigned int n) { /*modify b[i]*/ }

Lo stoccaggio puntato da array viene modificata anche attraverso b. Questo è ok con il secondo punto come &array[i*n] equivale a array+(i*n) (vedi §6.5.3.2).

Se b era limitare qualificato , allora avremmo controllare il quarto punto con Pb, Bfoo, P2array, B2bar. Poiché B è annidato all'interno B2 (funzioni si comportano come se inline qui, vedi §6.7.3.1.11), la prima condizione è soddisfatta. C'è anche uno instanciation del terzo punto (l'accesso ai b[i] in foo), che non è un problema.

Tuttavia b non è limita-qualificato. Secondo §6.3.2.3.2, “Per qualsiasi qualificazione q , un puntatore ad un non q tipo Qualificato può essere convertito in un puntatore alla q versione Qualificato del tipo; i valori memorizzati nei puntatori originali e convertiti confrontano uguali”. Pertanto la conversione da array+(i*n) a b è ben definito e ha il significato ovvio, quindi il comportamento del programma è definito. Inoltre, poiché non è b restrict qualificato, non ha bisogno di obbedire a qualsiasi condizione di linearità. Ad esempio, il seguente foo è legale in combinazione con bar:

void qux(float *v, float *w) {
    v[0] += w[0];
}
void foo(float* b, float c, unsigned int n)
{
    qux(b,b);
}

AGGIUNTO : Per affrontare la vostra specifica preoccupazione “in bar (), dove si passa l'indirizzo della parte della matrice di foo ()”, questo è un non-problema: restrict si applica al ppuntatore, non è l'array, ed è possibile eseguire operazioni aritmetiche su di esso (proiettile punto 2).

Altri suggerimenti

No, limitare i mezzi tale matrice non può alias nulla, in modo da poter passare roba da bar senza infrangere le regole

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