Un avviso del compilatore per troncamento 'size_t' da 64 bit a 32 bit è effettivamente utile?

4

Ho letto C4267

di VC ++

Compiler Warning (level 3) C4267

'var' : conversion from 'size_t' to 'type', possible loss of data

The compiler detected a conversion from size_t to a smaller type.

To fix this warning, use size_t instead of type. Alternatively, use an integral type that is at least as large as size_t.

Ho osservato questo aspetto e - forse non sorprendentemente - quando convertiamo una base di codice a 32 bit in 64 bit, là un lotti di questi errori, principalmente wrt. vector.size() ecc.

Note:

  • /W3 è il livello predefinito in VC ++, quindi questo è un avviso predefinito.
  • L'avviso viene attivato solo per size_t - anche se è "solo" a typedef per unsigned __int64 , se usi uint64 direttamente, l'avviso isn ' t attivato per quanto posso dire.

Ora, questo mi ha fatto meravigliare, puramente a livello concettuale, che questo avvertimento del compilatore abbia davvero senso per il 64% di size_t = > Tipo a 32 bit?

size_t , è un typedef utilizzato per le dimensioni. Principalmente std raccolte ecc. Nel codice di livello inferiore per le dimensioni della memoria grezza.

Come tale, il troncamento di questi valori da 64 bit a 32 bit produrrà risultati errati IFF della dimensione in questione > 4G. Questo è molto, intendo davvero molto per i conteggi di dati del mondo reale.

Il troncamento a 16 bit o 8 bit merita certamente un avvertimento, ma questo non viene gestito separatamente qui. Come tale, ho l'impressione che questo avviso predefinito fornisca più rumore che valore per la maggior parte degli sviluppatori.

Questo avvertimento fornisce alcuni vantaggi reali che mi mancano qui? O è davvero semplicistico? Forse / forse mi manca un caso d'uso importante per size_t ?

    
posta Martin Ba 20.10.2016 - 13:11
fonte

4 risposte

9

The warning is triggered only for size_t -- even though it is "just" a typedef for unsigned __int64, if you use uint64 directly, the warning isn't triggered as far as I can tell.

Ma uint64_t non ha cambiato le dimensioni quando sei passato a 64 bit e size_t lo ha fatto.

Il compilatore non ti avvisa solo perché si tratta di una conversione restringente, anche se potrebbe essere su un altro livello.

Ti avverto perché il codice che in precedenza utilizzava uint32_t per size_t , ora è stato modificato in modo silenzioso con uint64_t , e questo potrebbe causare bug sorprendenti senza modifiche visibili nel codice.

    
risposta data 20.10.2016 - 13:26
fonte
2

I have been looking at this, and - maybe unsurprisingly - when converting a 32 bit code base to 64 bit, there a lots of these errors, mainly wrt. vector.size() etc.

Questi avvertimenti sono un segnale che gli sviluppatori che invocano tali metodi non hanno prestato attenzione ai tipi di ritorno. Il fatto che ce ne siano molti significa che il fallimento è stato ripetuto molte volte.

La domanda da porre è perché, quando la libreria offre un tipo di ritorno garantito per funzionare correttamente ogni volta ( size_type nel caso di vector.size() ), i chiamanti usano qualcos'altro ? Per mettere un punto più delicato e folksier su di esso, perché hanno portato una busta da cinque chili quando sapevano benissimo che qualcuno avrebbe potuto chiedergli di aggiungervi dieci sterline di qualcosa?

Ci sono casi legittimi in cui potresti avere un intero più grande a portata di mano che deve essere inserito in uno spazio più piccolo. Quando incontri queste situazioni, ci sono delle misure che puoi prendere per assicurarti che avvengano in sicurezza e senza un avvertimento del compilatore.

Now, this made me wonder, purely on a conceptual level, does this compiler warning actually make any sense for the 64bit size_t => 32bit type?

Se stai scrivendo un codice concettuale, non importa un po '. Nessuno dei codici nei miei sistemi è concettuale e i compilatori sono strumenti per gestire il codice reale che si intende eseguire. Per questo, conta molto.

Vuoi che i tuoi programmi spuntino bug?

size_t func() { return 4294967296; }
uint32_t returned;
returned = func();
if ( returned == 0 ) {
    // This block will be executed.  FAIL.
}

E i problemi di sicurezza?

BugHugeThing thing;
uint32_t how_big = sizeof thing;
BigHugeThing *other_thing = malloc(how_big);
// ...elsewhere...
memcpy(other_thing, &thing, sizeof *other_thing);  // Buffer overflow.  FAIL.

...truncating these values from 64bit to 32bit will produce erroneos results IFF the size in question > 4G. That's a lot, I mean really a lot for real world data counts.

Questo è un IFF molto grande. Sei disposto a mettere in gioco la tua reputazione professionale partendo dal presupposto che tali troncamenti non causeranno mai problemi?

4G può sembrare un gran numero nel tuo mondo, ma non è nel mio, dove set di dati con più elementi di quelli che vengono generati e spediti quotidianamente e elaborati su sistemi in grado di inalare tutto. Uno show televisivo che hai guardato potrebbe essere stato girato in 4K, dove il troncamento di un size_t a 32 bit a 64 bit ha perso l'accesso a tutti i primi due minuti di filmato provenienti dalla videocamera.

Bottom line: i tipi di restituzione esistono per un motivo. Usali.

    
risposta data 21.10.2016 - 01:07
fonte
1

Il tuo compilatore ha visto che tecnicamente esiste un potenziale errore nel tuo programma. Quindi l'avvertimento ha senso.

È il tuo lavoro di programmatore giudicare se è necessario correggere questo potenziale bug o ignorarlo.

Personalmente, direi di aggiustarlo. Ma questo è un giudizio umano. Un computer non è costruito per farlo. Può solo dirti i fatti e il fatto è che c'è un potenziale errore nel tuo codice per almeno un ramo possibile.

Se non trovi utile l'avviso, spegnilo. Non svanirà certamente dal compilatore, perché altre persone con un diverso giudizio umano potrebbero volerne approfittare.

    
risposta data 20.10.2016 - 13:21
fonte
1

Una ragione per gli avvertimenti size_t è che se va male, andrà davvero male. Diciamo che creo un libro con molte immagini e il numero totale di byte per ogni cosa è memorizzato in un size_t. E lo converti in uint32_t. Questo andrà storto quando il mio libro raggiunge i 4 GB di dimensione. In altre parole, in un punto in cui ho investito una quantità enorme di lavoro nella creazione del libro.

Oppure scrivi software solo da piccoli clienti, clienti di medie dimensioni e grandi clienti. Il cliente che si imbatterà nel tuo bug e perderà i dati sarà il cliente più grande, il più cattivo e il più cattivo che tu abbia, che masticherà te e la tua azienda.

(Per ragioni simili, MacOS X e probabilmente altri sistemi operativi a 64 bit rendono inaccessibili i primi 4GB di spazio di indirizzamento, in questo modo lanciando un puntatore valido a int o unsigned int e back never funzionerà, che è molto meglio che lavorare fino a quando i dati diventano grandi).

    
risposta data 20.10.2016 - 16:02
fonte

Leggi altre domande sui tag