2013-05-14 28 views
26

Il typecasting in C/C++ comporta cicli di CPU aggiuntivi?Il typecasting consuma più cicli della CPU

La mia comprensione è che dovrebbe consumare cicli di CPU aggiuntivi almeno in alcuni casi. Come typecasting da float a integer in cui la CPU dovrebbe richiedere la conversione di una float in intero.

float a=2.0; 
int b= (float)a; 

Mi piacerebbe capire i casi in cui non avrebbe/non avrebbe consumato cicli aggiuntivi della CPU.

+9

Dipende dal tipo di getto. –

+5

Dato che hai codificato questo C++, suggerirei l'uso del cast di stile C++, ovvero 'static_cast ', 'dynamic_cast ', 'reinterpret_cast ' e 'const_cast '. – JBL

+0

Anche escludendo tutti i dettagli relativi alla lingua e le minuzie, se un cast è "libero" o meno è probabilmente molto dipendente dalla piattaforma. Ad esempio, su x86, la maggior parte dei cast interi da più grandi a più piccoli sono gratuiti, ma questo potrebbe non essere il caso su un'altra piattaforma con caratteristiche diverse. – yzt

risposta

19

Vorrei dire che "la conversione tra i tipi" è ciò che dovremmo guardare, non se esiste un cast o meno. Ad esempio

int a = 10; 
float b = a; 

sarà lo stesso:

int a = 10; 
float b = (float)a; 

Ciò vale anche per cambiare la dimensione di un tipo, ad esempio

char c = 'a'; 
int b = c; 

questo "estenderà c in una dimensione int da un singolo byte [utilizzando byte nel senso C, non 8 bit senso]", che potenzialmente aggiungere un'istruzione supplementare (o clockcycle supplementare (s) alle istruzioni utilizzate) sopra e oltre il datamovement stesso.

Si noti che a volte queste conversioni non sono affatto ovvi. Su x86-64, un tipico esempio sta usando int invece di unsigned int per gli indici negli array. Poiché i puntatori sono a 64 bit, l'indice deve essere convertito in 64 bit. Nel caso di un unsigned, è banale: basta usare la versione a 64 bit del registro il valore è già in, poiché un'operazione di caricamento a 32 bit riempirà a zero la parte superiore del registro. Ma se hai uno int, potrebbe essere negativo. Quindi il compilatore dovrà usare l'istruzione "sign estendere questo a 64 bit". Questo in genere non è un problema in cui l'indice viene calcolato in base a un ciclo fisso e tutti i valori sono positivi, ma se si chiama una funzione in cui non è chiaro se il parametro è positivo o negativo, il compilatore dovrà sicuramente estendere il valore . Allo stesso modo, se una funzione restituisce un valore che viene utilizzato come indice.

Tuttavia, qualsiasi compilatore ragionevolmente competente non aggiungerà le istruzioni per convertire qualcosa dal proprio tipo a se stesso (probabilmente se l'ottimizzazione è disattivata, potrebbe farlo - ma l'ottimizzazione minima dovrebbe vedere che "stiamo convertendo da tipo X digitare X, ciò non significa nulla, portarlo via ").

Quindi, in breve, l'esempio sopra riportato non aggiunge penalità extra, ma ci sono certamente casi in cui "la conversione di dati da un tipo all'altro aggiunge istruzioni e/o clockcycles al codice".

+2

+1 per la mia distinzione preferita: cast verso conversioni. –

+1

non sempre importa per la modifica della dimensione, come in un registro generale ci sono alias per parti del registro ... ovviamente potrebbe ... ma anche in pila, a causa degli allineamenti si può in genere solo afferrare una versione più grande di un valore senza segno. –

+1

Ci sono due problemi nel rendere un valore più grande: 1. Cosa c'è nella "parte superiore", 2. Cosa DOVREBBE essere nella parte superiore. I valori senza segno, su x86-64 funzionano, in base alla progettazione, perché la parte superiore del registro è piena di zeri.Ma se si suppone che il registro sia esteso, è necessario riempirlo con qualunque sia il segno, il che significa che è necessaria un'ulteriore istruzione. Ovviamente, leggere 64-bit dallo stack probabilmente non funzionerà, in quanto non c'è assolutamente alcuna garanzia che i 32 bit superiori siano effettivamente il valore che si desidera. –

12

Consumerà cicli in cui altera la rappresentazione sottostante. Quindi consumerà cicli se si converte uno float in uno int o un vizio. A seconda dell'architettura, ad esempio int a char o long long a int può o non può consumare cicli (ma il più delle volte lo faranno). La trasmissione tra i tipi di puntatore comporterà solo cicli se è coinvolta più eredità.

+2

Solo un piccolo commento. long long to int non dovrebbe consumare cicli solo nei casi in cui sizeof (long long) == sizeof (int). – vishal

3

DL e godere di manuali d'Agner Fog:
http://www.agner.org/optimize/
1.Ottimizzare il software in C++: Una guida di ottimizzazione per le piattaforme Windows, Linux e Mac
E 'enorme PDF, ma per cominciare si può verificare:

14,7 Non mescolare float e double
14,8 conversioni tra numeri in virgola mobile e numeri interi

7

Esistono diversi tipi di calchi. C++ ha diversi tipi di operatori di cast per i diversi tipi di cast. Se guardiamo in questi termini, ...

static_cast di solito avrà un costo se stai convertendo da un tipo all'altro, soprattutto se il tipo di destinazione è una dimensione diversa rispetto al tipo di origine. I numeri static_cast vengono talvolta utilizzati per trasmettere un puntatore da un tipo derivato a un tipo di base. Questo può anche avere un costo, specialmente se la classe derivata ha basi multiple.

reinterpret_cast di solito non ha un costo diretto. In poche parole, questo tipo di cast non modifica il valore, cambia solo il modo in cui viene interpretato. Si noti, tuttavia, che questo potrebbe avere un costo indiretto. Se si reinterpretano un puntatore a una matrice di byte come puntatore a un int, allora si può pagare un costo ogni volta che si denomina quel puntatore a meno che il puntatore non sia allineato come previsto dalla piattaforma.

const_cast non dovrebbe costare nulla se si aggiunge o si rimuove la costanza, in quanto è principalmente un'annotazione per il compilatore. Se la stai usando per aggiungere o rimuovere un qualificatore volatile, suppongo che ci possa essere una differenza di prestazioni perché abiliterebbe o disabiliterebbe determinate ottimizzazioni.

dynamic_cast, che viene utilizzato per trasmettere da un puntatore a una classe base a un puntatore a una classe derivata, sicuramente ha un costo, in quanto deve, come minimo, verificare se la conversione è appropriata.

Quando si utilizza un cast tradizionale in C, si sta essenzialmente chiedendo al compilatore di scegliere il tipo di cast più specifico. Quindi, per capire se il tuo cast di C ha un costo, devi capire che tipo di cast è veramente.

+0

Sì, devono essere davvero 2 domande una per il codice C, che è tipicamente una distinzione a livello di assembly e codice C++ che potrebbe finire per eseguire gli inizializzatori e il codice del template e potrebbe essere un 1000 operazioni per un cast che sembra abbastanza semplice, e è automatico dal punto di vista dei programmatori. –

Problemi correlati