2015-07-09 19 views
14

Qualcuno può chiarire se (e perché) una funzione può essere attribuita pure o const se ha un parametro puntatore.Funzioni GCC pure/const che accettano un argomento del puntatore

Secondo il GCC documentation:

Alcuni degli esempi comuni di funzioni pure sono strlen o memcmp.

Il punto centrale di una funzione pura è che deve essere chiamato solo una volta per gli stessi parametri, vale a dire il risultato può essere memorizzato nella cache se il compilatore pensa che sia adatta a farlo, ma come fa questo lavoro per memcmp?

ad esempio:

char *x = calloc(1, 8); 
char *y = calloc(1, 8); 

if (memcmp(x, y, 8) > 0) 
    printf("x > y\n"); 

x[1] = 'a'; 
if (memcmp(x, y, 8) > 0) 
    printf("x > y\n"); 

I parametri per la seconda chiamata a memcmp sono identici alla prima (i puntatori puntano allo stesso indirizzo), come non al compilatore di utilizzare il risultato della prima chiamare, se memcmp è puro?

Nel mio caso, voglio passare una matrice a una funzione pura e calcolare il risultato in base alla sola matrice. Qualcuno mi rassicura che questo è ok, e che quando i valori nella matrice cambiano ma l'indirizzo no, la mia funzione verrà chiamata correttamente.

risposta

3

Per quanto riguarda il puro possiamo vedere dall'articolo Implications of pure and constant functions che significa puro che la funzione non ha effetti collaterali e dipende solo dai parametri.

Quindi, se il compilatore può determinare che gli argomenti sono gli stessi e la memoria non è cambiata tra chiamate successive, può eliminare le chiamate successive alla funzione pura poiché sa che la funzione pura non ha effetti collaterali.

Ciò significa che il compilatore deve fare analisi per essere in grado di determinare se gli argomenti della funzione pura potrebbero essere stati modificati prima di poter decidere di eliminare le chiamate successive a una funzione pura per gli stessi argomenti.

Un esempio dall'articolo è la seguente:

int someimpurefunction(int a); 
int somepurefunction(int a) 
    __attribute__((pure)); 

int testfunction(int a, int b, int c, int d) { 

    int res1 = someimpurefunction(a) ? someimpurefunction(a) : b; 
    int res2 = somepurefunction(a) ? somepurefunction(a) : c; 
    int res3 = a+b ? a+b : d; 

    return res1+res2+res3; 
} 

e mostra generato il gruppo ottimizzato che dimostra che somepurefunction stato chiamato solo una volta e poi dice:

Come si può vedere, la pura funzione viene chiamata una sola volta, perché i due riferimenti all'interno dell'operatore ternario sono equivalenti, mentre l'altro viene chiamato due volte. Questo perché non è stata apportata alcuna modifica alla memoria globale nota al compilatore tra le due chiamate della funzione pura (la funzione stessa non può modificarlo - si noti che il compilatore non prenderà mai in considerazione il multithreading, anche quando richiede per esplicitamente attraverso il flag -pthread), mentre la funzione non pura può cambiare la memoria globale o utilizzare le operazioni di I/O.

Questa logica si applica anche a un puntatore, quindi se il compilatore in grado di dimostrare la memoria indicò il puntatore non è stato modificato, allora si può eliminare la chiamata alla funzione pura Quindi nel tuo caso in cui il compilatore vede:

x[1] = 'a'; 

non può eliminare la seconda chiamata a memcmp perché la memoria puntata da x è cambiato.

+1

Grazie per il collegamento dell'articolo, interessante. Ma la mia domanda riguardava specificamente gli argomenti del puntatore alle funzioni pure. – jsj

+0

@ trideceth12 la stessa analisi si applica anche ai puntatori. –

+0

Quindi cosa succede se 8 e 1 non sono noti al momento della compilazione? Per esempio. sono variabili? – Kata

3

Se ho letto correttamente la documentazione, una funzione pure può dipendere dai valori della memoria, dove il compilatore sa quando cambia la memoria. Inoltre, una funzione pure non può modificare lo stato del programma, ad esempio una variabile globale, produce solo un valore di ritorno.

Nel codice di esempio, memcmp può essere una funzione pure. Il compilatore vede che la memoria viene cambiata tra le chiamate a memcmp e non può riutilizzare il risultato della prima chiamata per la seconda chiamata.

D'altra parte, può memcmpnon essere dichiarato come funzione const, poiché dipende dai dati in memoria. Se fosse const, il compilatore poteva applicare ottimizzazioni più aggressive.

Per questo motivo, sembra sicuro dichiarare la funzione che si desidera implementare come pure (ma non const).

Problemi correlati