2013-09-26 6 views
11

C'è un modo per dire a un compilatore C99 che l'unico modo per accedere a un determinato array è usare myarray [index]? dire qualcosa del genere:Utilizzare restrizioni con gli array?

int heavy_calcualtions(float* restrict range1, float* restrict range2) 
{ 
    float __I promise I won't alias this__ tmpvalues[1000] = {0}; 

    .... 
    heavy calculations using range1, range2 and tmpvalues; 
    .... 
} 

Utilizzando limitare ho promesso che non mi alias range1 e range2, ma come faccio a fare la stessa cosa per matrice dichiarata dentro la mia funzione?

+0

Che tipo di avvertimento lancia? – dhein

+1

"invalid use of restrict" - dovrebbe essere usato con puntatori, non array (per quanto ho capito). Potrei fare float * limitare tmpvalues ​​= malloc (sizeof (float) * 1000) ma poi non sto allocando sullo stack che potrebbe influenzare anche le prestazioni. Oltre a dire a un compilatore che l'accesso agli indici di array è sicuro (quindi non sono necessarie letture difensive) sembra un'estensione molto naturale dell'uso limitato con i puntatori in modo così intuitivo che ci deve essere un modo per farlo. –

+1

Ho fatto: float * limita tmpvalues ​​= alloca (sizeof (float) * 1000); memset (tmpvalues, 0, sizeof (float) * 1000); ed è un miglioramento misurabile, ma preferirei farlo in standard (come nel caso di denuncia C99) –

risposta

3

Perché non riesci a fare quanto segue? Non si sta accedendo ai dati associati a tmpvalues tramite tale variabile, quindi è valido utilizzare un puntatore a restrizione nella porzione di codice ad alta intensità di calcolo.

#include <stdio.h> 
#include <stdlib.h> 

int heavy_calcs(int n, float* restrict range1, float* restrict range2) 
{ 
    if (n>1000) return 1; 
    float tmpvalues[1000] = {0}; 
    { 
     float * restrict ptv = tmpvalues; 
     for (int i=0; i<n; i++) { 
      ptv[i] = range1[i] + range2[i]; 
     } 
    } 
    return 0; 
} 

int main(int argc, char * argv[]) 
{ 
    int n = (argc>1) ? atoi(argv[1]) : 1000; 
    float * r1 = (float*)malloc(n*sizeof(float)); 
    float * r2 = (float*)malloc(n*sizeof(float)); 
    int rc = heavy_calcs(n,r1,r2); 
    free(r1); 
    free(r2); 
    return rc; 
} 

ho eseguito questo attraverso il compilatore Intel 15 e non ha avuto problemi vettorizzazione del ciclo. Certo, questo ciclo è banale rispetto a quello che presumo sia il tuo, quindi il tuo chilometraggio può variare.

+0

[Non è necessario eseguire il cast di 'malloc' in C] (http: // stackoverflow.it/q/605845/995714) –

+1

Non c'è nemmeno bisogno del '{}' attorno al compito 'ptv'. – Jeff

10

Anche se la risposta di Jeff è giusto, vale a dire, si può sempre fare un puntatore alla matrice assegnato, il fatto è che il compilatore sa a tempo di compilazione che tmpvalues ​​non saranno alias perché la variabile è dichiarata come un matrice reale, non un puntatore. Le uniche possibilità di alias di un array è dichiarare un puntatore ad esso, quindi se non lo fai, non è necessario dichiararlo come restrict. Questo è più evidente se tmpvalues è l'unica variabile che avrai all'interno della funzione.

Il problema può sorgere se si passa il puntatore a un'altra funzione, quindi è necessario indicare se il puntatore ricevuto è limitato o meno.

La documentazione che ho incontrato relativa a questo argomento vengono presentate le C99:

Sia D una dichiarazione di un identificatore normale che fornisce un mezzo di designare un oggetto P come puntatore limitare qualificato per tipo T

Si noti che si applica solo ai puntatori.

This other document di TI fornisce alcuni suggerimenti di ottimizzazione delle prestazioni utilizzando la parola chiave restrict. Oltre a tutti i suggerimenti, la sezione 3.3 fornisce esempi quando è possibile applicare questo qualificatore di tipo e quando no. Cerca la dichiarazione dell'array x a metà di pagina 16, afferma che non dichiara un puntatore e quindi non può essere restrict -qualificato.

+0

Se un puntatore all'array viene passato al codice esterno, non esiste un modo pulito per indicare che il codice esterno non manterrà una copia del puntatore e utilizzerà tale copia per scopi arbitrari la prossima volta che viene invocato il codice esterno. IMHO sarebbe stato utile per C avere un qualificatore simile a 'restrict', ma per l'uso con variabili il cui indirizzo è stato preso ma sarà usato solo in modi molto limitati, ma nessuna di queste caratteristiche è definita. – supercat

+0

@supercat un problema è - come definite questi "vari modi"? gcc ha attributi (come 'pure') che possono essere associati a funzioni, che promettono che la funzione non eseguirà determinate classi di cose. Oltre a ciò, ora disponiamo di "ottimizzazione del tempo di collegamento", in cui il set di strumenti del compilatore può fondamentalmente esaminare ciò che la funzione sta effettivamente facendo e utilizzare tali informazioni. – greggo

+0

@greggo: Se scrivessi le regole, direi che un oggetto qualificato 'register' può avere solo il suo indirizzo preso nella valutazione di un argomento di funzione, e il comportamento sarebbe definito solo nei casi in cui tutti gli usi del risultante il puntatore o i puntatori da esso derivati ​​avvengono prima che la funzione ritorni, e durante l'esecuzione della funzione (1) l'accesso all'oggetto avviene esclusivamente tramite il puntatore risultante o altri derivati ​​da esso, oppure (2) l'oggetto non viene modificato con alcun mezzo. Se un processo di compilazione inizia con la costruzione di un elenco di tutti i simboli esterni utilizzati in ogni funzione ... – supercat

Problemi correlati