Domanda

che sto facendo un sacco di matrice aritmetica e vorrei approfittare di qualificazione puntatore restrict di C99.

Mi piacerebbe impostare il mio matrici come puntatori a puntatori per consentire un facile subscripting, in questo modo:

int **A = malloc (ncols * sizeof(int *));
A[0] = malloc (nrows * ncols * sizof(int));
for (int i=1; i < ncols; i++) {
    A[i] = A[0] + i*nrows;
}

Ora, per una funzione di matrice moltiplicazione

void mmultiply ( int nrows, int ncols, int **Out, int **A, int **B);

devo qualificare entrambi i puntatori degli argomenti come limitato? E 'sintassi valida, ma sto avendo un momento difficile determinare se int *restrict *restrict si comporta in modo diverso da int **restrict.

Poi, con i puntatori correttamente limitati, sta accedendo elementi attraverso A[0][col*nrows + row] indefinito? (Cioè, sarà il compilatore supporre che I solo accedere alla matrice attraverso A[col][row] per valori di row tali che row < nrow)? O devo semplicemente rimanere coerenti?

È stato utile?

Soluzione

Per la prima domanda, "sì", vorrà dire qualcosa di diverso se si utilizzano entrambe le qualificazioni restrict, in particolare, che i puntatori, inoltre, non saranno alias. Quanto alla questione se non fa alcuna differenza: in teoria sì, in pratica, dipende l'ottimizzatore

.

Per la seconda domanda, "sì", si assumeranno che qualsiasi cosa si accede tramite un puntatore di riga si accede solo tramite il puntatore di riga.

Si potrebbe gettare const anche lì.

Infine, se questo è gcc a -O2, -O3 o -Os, il compilatore sta già facendo un'analisi alias in base ai tipi. Sono sicuro che altri compilatori lo fanno anche. Ciò significa che limitando i puntatori vs gli interi sono già conosciuti, lasciando solo le matrici che potrebbe memorizzare l'uno all'altro.

In sintesi, l'ottimizzatore assumerà che i puntatori non vengono memorizzati in come int, e sa che non sta facendo alcun puntatore scrive durante il ciclo.

Quindi, probabilmente otterrete lo stesso codice con solo quella limitare.

Altri suggerimenti

L'esterno (secondo) limitare dice al compilatore che nessuno dei vettori di puntatori (A, B, e fuori) alias. L'interno (prima) limitare dice al compilatore che nessuna delle matrici di interi (puntato da elementi delle matrici di puntatori) alias.

Se si accede sia A [0] [col * nrows + riga] e A [col] [riga] allora stai violando limitano l'interno, quindi le cose potrebbero rompersi.

int **restrict afferma solo che la memoria indirizzata da fuori, A e B non si sovrappongono (tranne che A e B può sovrapporsi, assumendo la funzione non modifica una di esse). Questo significa che gli array di puntatori. Essa non afferma nulla circa il contenuto della memoria puntato da OUT, A e B. La nota 117 in n1124 dice:

  

se identificatore p è di tipo (int   ** limitare), allora le espressioni puntatore P e P + 1 si basano sulla   ristretta oggetto puntatore designato   da p, ma le espressioni puntatore * p   e p [1] non sono.

Per analogia con const, ho il sospetto che le qualifiche con il doppio restrict sarà valere ciò che si vuole, che è che nessuno dei valori nei punti di matrice per sovrapposizione di memoria. Ma la lettura della norma, non posso dimostrare a me stesso che in realtà fa. Mi sa che "Sia D una dichiarazione di un identificatore comune che fornisce un mezzo per designare un oggetto P come puntatore restringere qualificato per digitare T" implica certamente per int *restrict *restrict A, allora A [0] e A [1] sono oggetti designati come puntatore limitare qualificato per int. Ma è legalese piuttosto pesante.

Non ho idea se il compilatore effettivamente fare nulla con questa conoscenza, sia chiaro. Chiaramente il possibile, è una questione di se è implementato.

Quindi non so davvero che cosa hai guadagnato nel corso di un convenzionale C gamma 2-D, dove basta allocare rows * cols * sizeof(int), e l'indice con A[cols*row + col]. Quindi è chiaramente necessario un solo utilizzo di limitare, e qualsiasi compilatore che fa qualsiasi cosa con restrict sarà in grado di ri-ordinare legge da A e B scrive tutto a Out. Senza restrict, ovviamente, non può, in modo da fare quello che stai facendo, si sta gettando da soli sulla misericordia del compilatore. Se non riesce a far fronte con doppio limitare, solo il caso singolo limitare, allora il vostro doppio riferimento indiretto si è costato l'ottimizzazione.

In prima ipotesi, la moltiplicazione è probabile che sia più veloce di un ulteriore riferimento indiretto puntatore comunque. È, ovviamente, preoccupate per le prestazioni o non sarebbe utilizzando limitare a tutti, quindi mi piacerebbe provare le prestazioni abbastanza accuratamente (su tutti i compilatori che ti interessano) prima di fare questo cambiamento per il bene di sintassi leggermente più bello e non dover ricordare quanti colonne ci sono nella propria matrice ogni volta che vi si accede.

accede attraverso elementi A [0] [col * nrows + riga] indefinito?

Sì, se l'elemento viene modificato da uno degli accessi, perché questo rende A [0] alias di memoria anche accessibili tramite un [col]. Sarebbe bene se solo A e B erano puntatori limitare qualificati, ma non se A [0] e A [col] sono.

Suppongo che non si modificano A in questa funzione, in modo che in realtà alias va bene. Se avete fatto la stessa cosa con fuori, però, il comportamento sarebbe definito.

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