Solo un paio di settimane fa, ho appreso che lo standard C++ aveva una rigida regola di aliasing. Fondamentalmente, avevo fatto una domanda sullo spostamento dei bit - piuttosto che spostare ogni byte uno alla volta, per massimizzare le prestazioni volevo caricare i registri nativi del mio processore con (32 o 64 bit, rispettivamente) ed eseguire lo spostamento del 4/8 byte tutti in una singola istruzione.Rigida regola di aliasing del C++ - L'esonero di aliasing 'char' è una strada a doppio senso?
Questo è il codice che volevo evitare:
unsigned char buffer[] = { 0xab, 0xcd, 0xef, 0x46 };
for (int i = 0; i < 3; ++i)
{
buffer[i] <<= 4;
buffer[i] |= (buffer[i + 1] >> 4);
}
buffer[3] <<= 4;
E invece, ho voluto usare qualcosa come:
unsigned char buffer[] = { 0xab, 0xcd, 0xef, 0x46 };
unsigned int *p = (unsigned int*)buffer; // unsigned int is 32 bit on my platform
*p <<= 4;
Qualcuno gridò in un commento che la mia soluzione proposta ha violato il C++ Regole di aliasing (perché p era di tipo int*
e buffer era di tipo char*
e stavo dereferenziando p per eseguire il turno. (Si prega di ignorare eventuali problemi di allineamento e ordine dei byte - gestisco quelli al di fuori di questo frammento) Sono rimasto piuttosto sorpreso t o impara a conoscere la regola di Aliasing severo dato che lavoro regolarmente su dati provenienti da buffer, lo lancio da un tipo all'altro e non ho mai avuto alcun problema. Ulteriori indagini hanno rivelato che il compilatore che uso (MSVC) non applica regole rigorose di aliasing e dal momento che sviluppo solo su gcc/g ++ nel mio tempo libero come hobby, probabilmente non avevo ancora riscontrato il problema.
Allora ho fatto una domanda sulle regole Aliasing rigorosa e C++ s 'Posizionamento nuovo operatore:
IsoCpp.org offre una FAQ per quanto riguarda il posizionamento nuovo e forniscono il seguente esempio di codice:
#include <new> // Must #include this to use "placement new"
#include "Fred.h" // Declaration of class Fred
void someCode()
{
char memory[sizeof(Fred)]; // Line #1
void* place = memory; // Line #2
Fred* f = new(place) Fred(); // Line #3 (see "DANGER" below)
// The pointers f and place will be equal
// ...
}
L'esempio è abbastanza semplice, ma mi chiedo: "Che cosa succede se qualcuno chiama un metodo su f
- ad es. f->talk()
? A quel punto ci sarebbe il dereferenziamento f
, che punta alla stessa posizione di memoria di memory
(di tipo char*
. Ho letto numerosi posti s che esiste un'esenzione per le variabili di tipo char*
per l'alias di qualsiasi tipo, ma avevo l'impressione che non fosse una "strada a doppio senso" - ovvero, char*
può alias (lettura/scrittura) qualsiasi tipo T
, ma digitare T
può essere utilizzato solo per alias un char*
se T
è di char*
. Mentre sto scrivendo questo, non ha senso per me e quindi mi sto appoggiando alla convinzione che l'affermazione che il mio esempio iniziale (bit shifting) abbia violato la rigida regola dell'aliasing è falsa.
Qualcuno può spiegare, per favore, cosa è corretto? Vado dadi con il tentativo di capire ciò che è legale e ciò che non è (pur avendo letto numerosi siti web e così i messaggi sul tema)
Grazie
Se chiamare funzioni membro di 'f' fosse un comportamento indefinito, ciò renderebbe il posizionamento di nuovo tipo di inutile no? – Barry
"che punta alla stessa posizione di memoria della memoria (di tipo char *)" - il tipo di 'memoria' non è' char * '. Sulla linea 2 l'array decade in un puntatore, ma ciò non significa che 'memory' è un puntatore. E, anche se 'memoria' era un puntatore, il tipo di posizione della memoria a cui puntava sarebbe' char', non 'char *'. – davmac
Sembra che la tua domanda riguardi se 'f-> talk()' è OK; Penso che migliorerebbe la domanda di cancellare tutto il preambolo (la roba prima di "Allora") –