2010-11-18 9 views
6

Non credo che sia possibile evitare completamente i cast in stile C durante la scrittura di C++. Sono stato sorpreso di find out che avevo bisogno di utilizzare un cast C-style per evitare un avviso del compilatore troncamento:È possibile evitare completamente i cast in stile C in C++?

short value_a = 0xF00D;      // Truncation warning in VS2008 
short value_b = static_cast<short>(0xF00D); // Truncation warning in VS2008 
short value_c = (short)0xF00D;    // No warning! 

ci sono altri scenari in cui non c'è C++ - sostituto di stile per un cast C-style?

+7

'short value_c (0xF00D)' - anche: quale compilatore ti sta fornendo avvisi di troncamento? Il mio GCC è abbastanza intelligente da non trovarsi in tutte e tre le situazioni. –

+0

C++ esegue il cast di copertura per tutti gli usi dell'operatore di cast di C. – wilhelmtell

+8

Per quanto riguarda il linguaggio, in questo caso non c'è differenza tra 'static_cast' e un cast in stile C.Se il compilatore ha deciso di dare un avvertimento che "sono le 3:00 ora locale - dovresti davvero andare a letto", è comunque libero di farlo ... –

risposta

2

Stai solo cercando di offuscare il codice, è così semplice. E il compilatore è completamente corretto nel dirti così.

Se hai un'idea precisa su quale dovrebbe essere il valore assegnato, usa quello. La mia ipotesi è che si abbia qualche presunzione infondata di short larga 16 bit e che la rappresentazione del segno della macchina target sia il complemento a due. Se è così, assegna -4083 alla tua variabile. Se hai solo bisogno della tua variabile come vettore bit, usa un tipo senza segno.

Per quanto concerne C standard dice semplicemente di conversione da un tipo ad un altro numero intero:

Altrimenti, il nuovo tipo è firmata e il valore non può essere rappresentato in esso; o il risultato è definito dall'implementazione o un segnale definito dall'implementazione è generato.

Immagino che il punto di vista del C++ con questo rispetto non sia molto diverso. Altre risposte menzionano casi di confine in cui in C++ è necessario un cast di tipo C'per sovrascrivere tutti i tipi di ceckeck forniti da C++. Sentire il bisogno per loro è un'indicazione di cattivo design.

Il caso che si presta come esempio non è certamente un caso per il quale troverei alcuna circostanza valida.

-3

In questi casi, è possibile utilizzare reinterpret_cast. Era pensato per la sostituzione di un cast in stile C non controllato. La nota tipica qui: questa è una dominante non controllata e dovrebbe essere evitata quando possibile utilizzando l'altra disponibile: const_cast, dynamic_cast, ecc.

+1

In realtà, il cast in stile C può essere una delle 5 combinazioni di 'static_cast',' const_cast' e 'reinterpret_cast'. – kennytm

+0

Buona risposta..blah, blah, blah ... yadda, yadda ... non usare questo metodo a meno che non sia assolutamente necessario. –

+12

Non penso che un 'reinterpret_cast' debba essere usato per troncare un' int' a un 'short'. Mai. – sbi

2

Sì, è completamente possibile.

Non uso mai i cast di tipo C. Posso scrivere centinaia di migliaia di linee di codice senza dover tornare a utilizzare reinterpret_cast, cugino di C++ per chiudere il cast in stile C. Le uniche volte che devo usare reinterpret_cast è quando si esegue la programmazione di socket - un dominio abbastanza ristretto, nel quadro generale.

È non lo fanno necessità di utilizzare C-style cast, neanche. Nella tua other post, hai detto

ho potuto solo usare un valore negativo,

short my_value = -4083; 

ma nel mio codice è molto più comprensibile da usare esadecimale.

Quindi in questo caso non è necessario utilizzare il cast. Hai scelto di

+0

Recentemente, ho dovuto usare un reinterpret_cast per convertire da un array di caratteri grezzi non firmato a un'istanza di una struttura. È qualcosa di simile a ciò che stavi dicendo, a proposito delle prese? –

+0

@San. Può essere. :) Dovrei vederlo. –

+2

Mi piacerebbe votare per contrastare l'inesplicabile down-vote, ma per oggi ho esaurito i voti. ': (' Ma, sì, anche per me, il LoC/'reinterpret_cast' ration è da qualche parte nei numeri a sei cifre, e non penso di aver usato un cast in stile c in codice C++ nell'ultimo decennio – sbi

0

sono stato sorpreso di scoprire che avevo bisogno di utilizzare un cast C-style per evitare un avviso del compilatore troncamento

vedo il contrario: Si utilizza un cast C-style a impedisce al compilatore di avvertire e vedo questo come un grave svantaggio del cast in stile C.

se si ritiene di sapere cosa si sta facendo, quindi chiudere il compilatore per questo caso utilizzando un modo specifico del compilatore. Ad esempio, per VC usare qualcosa di simile

#pragma warning(push, disable: XXXX) 
// code goes here 
#pragma warning(pop) 
+0

Non avrei mai pensato di farlo, probabilmente perché usiamo almeno 3 diversi compilatori/famiglie di compilatori per compilare lo stesso codice per target diversi, e un cast mi sembra più pulito rispetto a fare tutto il controllo del preprocessore per determinare il compilatore ogni volta che potrei avere appena usato un cast. Qual è il tuo pensiero? –

+2

@San: Sono stato parte di un progetto in cui la maggior parte del codice è stata compilata da una mezza dozzina di compilatori e versioni diverse di essi, per diverse implementazioni lib di std diverse. Tuttavia, la maggior parte di noi ha cercato di evitare l'uso di cast in stile C, perché bloccavano completamente il compilatore, impedendo che indicasse errori. (E ogni errore trovato tramite la compilazione vale 1000 trovato in fase di esecuzione, solitamente da un cliente.) Esperienza IME __differenti compilatori varieranno in maniera selvaggia in quello che avvertono comunque__, quindi di solito è necessario chiuderli (selettivamente) in luoghi diversi . – sbi

+0

Interessante, grazie. –

10

In C++, il cast C-style è definito (§5.4) in termini di C++ - stile getta. Quindi per ogni cast puoi fare C-style, c'è un cast in stile C++ corrispondente (quasi).

Il "quasi" è che i cast in stile C ignorano l'accessibilità della classe base. Cioè, non v'è alcun equivalente C++ - fusione di stile per il seguente:

struct foo {}; 
struct bar : private foo {}; 

bar b; 
foo* f = (foo*)&b; // only way this can be done in a well-defined manner 

Quindi, non è non strettamente di lingua possibile completamente fosso C-style cast. Ma il numero di aree in cui una (combinazione di) cast di stile C++ non è sufficiente è poco importante.


Quanto sopra è la "risposta alla lingua". Quello che stai vivendo non ha nulla a che fare con i cast di tipo C rispetto ai cast di C++, ma solo l'implementazione del compilatore. Gli avvertimenti sono assolutamente specifici per l'implementazione e non hanno nulla a che fare con C++.

Così non fanno l'errore di usare le tue scoperte su questo particolare compilatore in questa particolare situazione per la conclusione di cose su C++ in generale.

+0

'foo * f = reinterpret_cast (& b)'?Anche se sto assumendo che tu abbia dimenticato il '&' da 'foo * f = (foo *) b'. –

+0

@Travis: No. Il risultato di 'reinterpret_cast' è ** definito dall'implementazione **. Con il cast in stile C, si comporta come un 'static_cast' che non è definito dall'implementazione. – GManNickG

+0

@GMan: chiaramente, * non * si comporta come un 'static_cast' nel caso dell'OP. Altrimenti darebbe un avvertimento. Dato che non ce n'è, concludo che si comporta come il "reinterpret_cast" qui. O il compilatore ha un bug. Fai la tua scelta. –

0

Ci sono 4 stili in C++, const_cast, reinterpret_cast, static_cast e dynamic_cast. Essi funzionano come segue:

// const_cast casts away constness or adds it 
const int const_integer = 5; 
const_cast<int>(const_integer) = 3; 

// static_cast will perform standards defined casts and will 
// cast up or down a c++ inheritance hierarchy without checking the result of the cast 
struct b {}; 
struct a : public b {}; 
struct c {}; 
double value = static_cast<double>(0.0f); 
b* b_value = new b; 
a* a_value = static_cast<a*>(b_value); 

// dynamic_cast will perform any cast that static_cast will, but will check to see 
// if the cast makes sense. If the values are not pointers, this cast can throw 
b* value_b = new b; 
a* value_a = new a; 
b* new_b = dynamic_cast<b*>(value_a); // will return NULL 
a* new_a = dynamic_cast<a*>(value_b); // will not return NULL  

// reinterpret_cast will change any type to any other type, as long as the constness of the types is the same. 
// the behavior of this cast is implementation specific. 
double* a = new double; 
*a = 0.0f; 
int *b = reinterpret_cast<int*>(a); 

Un cast stile C in C++ cerca semplicemente di eseguire quei calchi in un ordine specifico fino a quando uno di loro lavora. Tale ordine è il seguente:

  • un const_cast
  • uno static_cast
  • uno static_cast seguito da un const_cast
  • un reinterpret_cast, o
  • un reinterpret_cast seguito da un const_cast.

Quindi, in breve, è possibile eseguire qualsiasi cast di tipo c in C++, perché un cast di stile c in C++ è solo una disposizione dei cast di stile C++. Prendilo?

+0

Vedi la mia risposta, quindi. Non tutti i casi possono essere sostituiti con cast di stile C++. – GManNickG

+1

Il tuo primo esempio di 'const_cast' ha come risultato un comportamento indefinito. –

+0

Come si ottiene un comportamento indefinito? – tyree731