2010-02-17 15 views
6

Sto eseguendo una routine di copia del blocco di memoria e ho bisogno di gestire blocchi di memoria grezza in blocchi efficienti. La mia domanda non riguarda la copia specializzata che sto facendo, ma come esaminare correttamente l'allineamento puntatore grezzo in C.Sintassi approvata per la manipolazione grezza del puntatore

Ho un puntatore raw di memoria, diciamo che è già lanciato come un char non nullo * . Nella mia architettura, posso copiare in modo molto efficiente la memoria in blocchi da 64 byte QUANDO È ALLINEATO A 64 byte. Quindi il trucco (standard) è che eseguirò una semplice copia di 0-63 byte "manualmente" alla testa e/o alla coda per trasformare la copia da un carattere arbitrario * di lunghezza arbitraria a un puntatore allineato a 64 byte con qualche multiplo di 64 byte di lunghezza.

Ora la domanda è: come legalmente "esaminate" un puntatore per determinare (e manipolare) il suo allineamento? Il metodo più ovvio è gettato in un intero e solo esaminare i bit:

char *pointer=something. 
int p=(int)pointer; 
char *alignedPointer=(char *)((p+63)&~63); 

nota qui Mi rendono conto che alignedPointer non punta alla stessa memoria, come puntatore ... questo è il "rastrellamento" puntatore su cui posso richiamare la mia copia efficiente, e gestirò manualmente ogni altro byte all'inizio.

Ma i compilatori (giustamente) impazziscono a lanciare un puntatore in un numero intero. Ma in quale altro modo posso esaminare e manipolare i bit inferiori del puntatore in LEGAL C? Idealmente, con compilatori diversi non riceverei errori o avvisi.

+0

Questo dovrebbe essere ok finchè 'int' ha le stesse dimensioni dei tipi di puntatore. –

+0

Puoi anche dare un'occhiata a http://stackoverflow.com/questions/1898153/how-to-determine-if-memory-is-aligned-testing-for-alignment-not-aligning/1898194 –

+0

Ah, ma si presuppone che i puntatori siano memorizzati in binario da MSB a LSB. Cosa abbiamo? * comportamento indefinito! * (detto nello stesso modo in cui il tipo di arma letale dice * immunità diplomatica! *) Solo perché funziona nel mondo reale non lo rende meno indefinito. ;-) –

risposta

7

Per i tipi di interi che sono abbastanza grande per contenere i puntatori, C99 stdint.h ha:

Per i dati lunghezze ci sono:

che sono stati in giro da ben prima C99.

Se la piattaforma non dispone di questi, è possibile massimizzare la portabilità del codice utilizzando ancora questi nomi di tipo e rendendo adatti gli typedef s.

+0

+1 mi ha battuto. –

+0

ah, ma come si ottiene un puntatore * allineato * da uno non allineato? – JustJeff

0

Invece di int, provare un tipo di dati che abbia le stesse dimensioni di un puntatore (INT_PTR su Win32/64). Forse il compilatore non impazzirebbe troppo. :) O utilizzare un sindacato, se la compatibilità a 64 bit non è importante.

1

Non credo che in passato le persone fossero riluttanti a fare il proprio bit-bang, ma forse l'attuale umore "non toccarlo" sarebbe favorevole a qualcuno che creava una sorta di libreria standard per l'allineamento puntatori. Mancando di una qualche specie di api ufficiale, non hai altra scelta che AND e OR la ​​tua via.

+1

+1 In passato, non esisteva il comportamento * non definito *. Se il tuo compilatore ha fatto ciò che volevi, è stato sufficiente. –

0

I puntatori del cast da e verso gli interi sono validi, ma i risultati sono definiti dall'implementazione. Vedere la sezione 6.3.2.3 della norma. L'intenzione sembra essere che i risultati siano ciò che chiunque si aspetterebbe che il sistema si aspettasse, e in effetti questo sembra essere il caso di routine nella pratica.

Se l'architettura in questione può manipolare in modo efficiente i puntatori e gli interi in modo intercambiabile, e il problema è solo se funzionerà su tutti i compilatori per quel sistema, la risposta è che probabilmente lo farà comunque.

(Certamente, se dovessi scrivere questo codice, penserei che va bene così com'è fino a prova contraria.La mia esperienza è stata che i compilatori per un determinato sistema si comportano tutti in modo molto simile a questo tipo di livello; la lingua suggerisce solo un particolare approccio, che tutti poi prendono.)

"Probabilmente funziona" non è un ottimo consiglio generale, quindi il mio suggerimento sarebbe semplicemente scrivere il codice che funziona, circondarlo abbastanza adatto #ifdef s che solo il compilatore noto lo compila e si rimanda a memcpy negli altri casi.

#ifdef è raramente l'ideale, ma è abbastanza leggero rispetto ad altre possibilità. E se è necessario un comportamento definito dall'implementazione o trucchi specifici del compilatore, le opzioni sono comunque abbastanza limitate.

+0

"il linguaggio assembly suggerisce solo un approccio particolare" - inizierò a usare questa frase nei dibattiti sul software, indipendentemente dall'applicabilità. – notJim