Si tratta di un uso non valido di limitare puntatori?
-
27-09-2019 - |
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 ()?
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
, lasciaL
essere qualsiasi Ivalue che ha&L
basato su P. SeL
viene utilizzato per accedere al valore dellaX
oggetto che designa, eX
è 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 aP
.- Ogni accesso che modifica
X
si considera anche di modificareP
, ai fini del presente sottoclausola.- Se
P
viene assegnato il valore di unE
espressione puntatore che si basa su un altroP2
puntatore di oggetto ristretta, associato bloccoB2
, allora o l'esecuzione diB2
inizia prima dell'esecuzione diB
, o l'esecuzione diB2
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 P
← b
, B
← foo
, P2
← array
, B2
← bar
. 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