2013-03-18 16 views
15

Il mio programma ha il compito comune di scrivere dati binari in un file, conforme a un determinato formato di file non di testo. Dal momento che i dati che sto scrivendo non sono già presenti in blocchi esistenti ma invece sono messi insieme byte per byte in fase di esecuzione, io uso std::ostream::put() invece di write(). Presumo che questa sia una procedura normale.C'è un modo ortodosso per evitare l'avvertimento del compilatore C4309 - "troncamento del valore costante" con l'output di file binari?

Il programma funziona bene. Utilizza sia std::stringstream::put() e std::ofstream::put() con interi esadecimali a due cifre come argomenti. Ma ricevo l'avvertenza del compilatore C4309: "troncamento del valore costante" (in VC++ 2010) ogni volta che l'argomento a put() è maggiore di 0x7f. Ovviamente il compilatore si aspetta un signed char e la costante è fuori portata. Ma non credo che un troncamento stia realmente accadendo; il byte viene scritto esattamente come dovrebbe.

Gli avvisi del compilatore mi fanno pensare che non sto facendo le cose nel modo normale e accettato. La situazione che ho descritto deve essere comune. C'è un modo comune per evitare un simile avvertimento del compilatore? O è questo un esempio di un inutile avvertimento del compilatore che dovrebbe essere semplicemente ignorato?

Ho pensato a due modi ineleganti per evitarlo. Potrei usare la sintassi come mystream.put(char(0xa4)) per ogni chiamata. O invece di usare std::stringstream Potrei usare std::basic_stringstream< unsigned char >, ma non penso che il trucco funzionerebbe con std::ofstream, che non è un tipo di modello. Sento che qui dovrebbe esserci una soluzione migliore, specialmente dal momento che lo ofstream è pensato per scrivere file binari.

I tuoi pensieri?

--EDIT--

Ah, mi sono sbagliato su std::ofstream non essere un tipo su modelli. In realtà è std::basic_ofstream<char>, ma ho provato questo metodo e ho capito che non funzionerà comunque per mancanza di metodi definiti e incompatibilità polimorfica con std::ostream.

Ecco un esempio di codice:

stringstream ss; 
int a, b; 
/* Do stuff */ 
ss.put(0); 
ss.put(0x90 | a); // oddly, no warning here... 
ss.put(b);  // ...or here 
ss.put(0xa4);  // C4309 
+4

Solo così siamo tutti chiari, puoi aggiungere un esempio di codice concreto alla tua domanda? –

+1

Sono abbastanza sicuro che gli autori di compilatori non abbiano il tempo di generare avvisi "inutili". –

risposta

17

ho trovato la soluzione che sono felice con. È più elegante rispetto alla trasmissione esplicita di ogni costante a unsigned char. Questo è quello che avevo:

ss.put(0xa4); // C4309 

Ho pensato che il "troncamento" stava accadendo nel implicitamente colata unsigned char a char, ma Cong Xu ha sottolineato che interi costanti si presume essere firmato, ed ogni uno più grande di 0x7f ottiene promosso da char a int. Quindi deve essere effettivamente troncato (ridotto a un byte) se passato a put().Usando il suffisso "u", posso specificare una costante intera senza segno e, se non è maggiore di 0xff, sarà una unsigned char. Questo è quello che ho ora, senza avvisi del compilatore:

ss.put(0xa4u); 
7
std::stringstream ss; 
ss.put(0x7f); 
ss.put(0x80); //C4309 

Come avete indovinato, il problema è che ostream.put() aspetta una char, ma 0x7F è il valore massimo per char, e qualsiasi cosa viene promosso a int . Si dovrebbe lanciare a unsigned char, che è largo quanto char così Sarà memorizzare qualsiasi cosa char fa e sicuro, ma anche rendere le avvertenze di troncamento legittima:

ss.put(static_cast<unsigned char>(0x80)); // OK 
ss.put(static_cast<unsigned char>(0xFFFF)); //C4309 
+1

Perché usi 'ss.put (static_cast (0x80));' invece di 'ss.put (unsigned char (0x80))' o 'ss.put ((unsigned char) 0x80)'? Un cast statico preferito per qualche motivo? –

+1

@SamKauffman, è solo il modo moderno di fare cast di C++. È più prolisso ma meno ambiguo e più sicuro. –

+0

@CongXu, grazie! Quello che hai scritto sulla promozione mi ha aiutato a capire cosa sta realmente accadendo. –