2016-03-25 10 views
33

C++ 11 ha introdotto lo alignas specifier per specificare l'allineamento di una variabile e lo alignof operator per richiedere l'allineamento predefinito di un tipo. Tuttavia, non vedo alcun modo per ottenere l'allineamento di una variabile specifica. Prendiamo il seguente esempio banale:Interroga l'allineamento di una variabile specifica

alignas(16) float* array; 

Ecco cosa possiamo fare a questo proposito:

  • alignof(float*) rendimenti 8, che ovviamente non è quello che vogliamo.
  • alignof(array) restituisce 16, che è esattamente ciò che vogliamo, ma questa è un'estensione del compilatore; alignof come specificato dallo standard non può essere utilizzato su una variabile specifica.
  • alignof(decltype(array)) restituisce 8, il che era abbastanza prevedibile ma non quello che vogliamo.
  • std::alignment_of è implementato in termini di alignof, quindi non aiuta molto.

Desidero un meccanismo per confermare che la variabile specifica array sia allineata su un limite di 16 byte. C'è qualcosa nello standard per eseguire tale query?

+0

* alignof * non deve fornire questo - restituisce un contratto minimo a * tempo di compilazione * - Si desidera un valore * in fase di esecuzione *. Una variabile specifica potrebbe benissimo essere * allineata al limite di una pagina *, ai confini dei megabyte o qualsiasi altra cosa in fase di esecuzione (cioè molto meglio di quanto promesso o richiesto). Prendi l'indirizzo della variabile e controlla che sia divisibile in base al valore di allineamento desiderato in modo uniforme. – tofro

+0

@tofro Giusto, ho dimenticato di specificarlo, ma mi aspettavo un po 'di "allineamento" per trasformarlo in un oggetto di runtime quando usato su un nome di variabile (immagino che sia ciò che fa l'estensione del compilatore). Non mi aspettavo che tutto fosse conosciuto in fase di compilazione. – Morwenn

+0

Non riesco a vedere se qualcosa come * # definisce ALIGNED8 (x) ((& (x) && 0x7) == 0) * non si adatta al tuo scopo o perché lo standard dovrebbe avere qualcosa che duplica questo semplice costrutto. – tofro

risposta

8

Si può provare con qualcosa di simile:

bool is_aligned(const volatile void *p, std::size_t n) 
{ 
    return reinterpret_cast<std::uintptr_t>(p) % n == 0; 
} 

assert(is_aligned(array, 16)); 

È possibile che questo assume uno spazio di indirizzamento piatto e che l'aritmetica su uintptr_t è equivalente a aritmetica su char *.

Mentre queste condizioni prevalgono per la maggior parte delle piattaforme moderne, nessuna delle quali è richiesta dallo standard.

è del tutto possibile per un'implementazione eseguire alcuna trasformazione quando lancia void * a uintptr_t purché la trasformazione può essere invertita quando lancia ritorno da uintptr_t a void * (vedi What is uintptr_t data type).

Ulteriori dettagli in N4201 (si propone, tra l'altro, l'operazione is_aligned()).


EDIT

è volatile necessaria qui?

Permette qualcosa di simile:

alignas(16) volatile float a; 

assert(is_aligned(&a, 16)); 

Senza volatile si ottiene l'errore

conversione non conosciuta da 'float * volatili' a 'const void *' per il 1 ° argomento

Ulteriori riferimenti:

+0

Posso capire perché una funzione standardizzata sarebbe utile se ha bisogno di quelle garanzie. N4201 [è stato rifiutato] (https://issues.isocpp.org/show_bug.cgi?id=61) però. – Morwenn

+0

@manlio, è 'volatile' necessario qui? E se è così, non dovrebbe essere 'const void * volatile'? – user5434231

+0

@ user5434231 Ho aggiunto alcuni riferimenti alla risposta – manlio

2

Si potrebbe provare questo:

template<size_t size, typename T> 
constexpr bool IsAlignedAs(const T& v) 
{ 
    return (reinterpret_cast<const size_t>(&v) % size) == 0; 
} 

std::cout << IsAlignedAs<16>(array) << std::endl; 
std::cout << IsAlignedAs<32>(array) << std::endl; 
+0

A proposito, è possibile utilizzare 'static_assert (IsAlignedAs <16> (array)," Array non allineato a 16 ");' per l'array, ma non è possibile utilizzare 'static_assert (IsAlignedAs <32> (array)," Array non allineato a 32 ");' poiché è indeciso al momento della compilazione se questo è vero o no. – Elijan9

+0

Non è un'espressione costante per clang. – Jarod42

+0

In effetti sembra specifico per gcc. Il controllo dell'allineamento di un indirizzo in fase di compilazione (prima di collegarlo alla sua posizione finale) sembrava già un po 'prematuro ... – Elijan9

4

Questo è attualmente gestita da EWG 98. Ho presentato a paper su questo:

Il alignas specificatore è applicabile agli oggetti, che colpisce la loro esigenza di allineamento, ma non il loro tipo. Pertanto non è attualmente possibile determinare il requisito di allineamento effettivo di un oggetto. Questo documento propone di consentire l'applicazione di alignof a oggetti e riferimenti.

Il meglio che è possibile fare in questo momento è definire una variabile separata che mantenga l'allineamento della variabile.

+1

Sono felice di vedere che altre persone ci hanno pensato e hanno iniziato a lavorarci :) – Morwenn

Problemi correlati