2010-10-04 28 views
6

Supponiamo di disporre di un array di grandi dimensioni che calcolo un indice e che passi a una seconda funzione. Come semplice esempio, qualcosa come:Si tratta di un uso non valido di puntatori limitati?

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); 
} 

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

risposta

9

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

La definizione formale di restrict è fornita al §6.7.3.1. Cito la sottoclaus più importante qui sotto. P è un puntatore aggiornato a restrict per digitare T il cui ambito è un blocco B. Un'espressione puntatore E si dice che sia basata suP se dipende dal valore di P stesso, non dal valore a P.

Durante ogni esecuzione di B, lasciate L essere qualsiasi Ivalue che ha &L basato su P. Se L è utilizzato per accedere al valore dell'oggetto X che designa, e X è anche modificato (con qualsiasi mezzo) , si applicano i seguenti requisiti:

  • T non deve essere qualificato.
  • Ogni altro valore utilizzato per accedere al valore di X deve anche avere l'indirizzo in base a P.
  • Ogni accesso che modifica X deve essere considerato anche per modificare P, ai fini del presente sottopunto.
  • Se P viene assegnato il valore di un'espressione puntatore E che si basa su un altro oggetto puntatore limitato P2, associato blocco B2, allora o l'esecuzione di B2 inizia prima dell'esecuzione di B, o l'esecuzione di B2 termina prima del compito.

Se questi requisiti non sono soddisfatti, il comportamento non è definito.


Vediamo quali sono le regole hanno da dire su accessi a parti del arraybar s' in foo. Iniziamo con array, un puntatore qualificato limitato dichiarato nella lista 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 modificato anche attraverso b. Questo è ok con il secondo punto elenco come &array[i*n] equivale a array+(i*n) (consultare §6.5.3.2).

Se b era limitare qualificato, allora dovremmo controllare il quarto punto con Pb, Bfoo, P2array, B2bar. Dal momento che B è nidificato all'interno di B2 (le funzioni si comportano come se fossero state sottolineate qui, consultare §6.7.3.1.11), viene soddisfatta la prima condizione. C'è anche un'istanziazione del terzo punto (l'accesso a b[i] in foo) che non è un problema.

Tuttavia, b non è qualificato. Secondo §6.3.2.3.2, "Per qualsiasi qualificatore q, un puntatore a un valore non q -qualified può essere convertito in un puntatore allo q - versione qualificata del tipo; i valori memorizzati nei puntatori originali e convertiti devono essere uguali ". Pertanto la conversione da array+(i*n) a b è ben definita e ha il significato ovvio, quindi il comportamento del programma è definito. Inoltre, dal momento che b non è restrict -qualificato, non è necessario rispettare alcuna 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 a foo () ", Questo non è un problema: restrict si applica al puntatore, non all'array, ed è possibile eseguire aritmetici su di esso (bullet point 2).

+1

Non posso dire se stai dicendo che è giusto o sbagliato, ma puntelli per distribuire completamente lo standard. –

+0

@Matt: il codice è corretto (in parte perché le regole delle restrizioni non stanno facendo molto qui, e in parte perché è possibile convertire il qualificatore restrittivo nel subscope delimitato da 'foo'). – Gilles

-1

No, limitare significa che array non può alias nulla, in modo da poter passare roba da bar senza infrangere le regole

+4

Penso che questa domanda richieda una citazione dalle spiegazioni standard e non casuali sulla falsariga di "limitare i mezzi ...". Le regole di aliasing C99 sono troppo complicate per fare affidamento su spiegazioni casuali del genere. –

+0

le regole per la restrizione sono piuttosto semplici, non possono essere raggiungibili attraverso qualsiasi cosa tranne il puntatore restrittivo. – Spudd86

Problemi correlati