9

Sto facendo programmazione ARM incorporata con gcc 4.9. Ho utilizzato lo switch -Wconversion perché si trova nella configurazione dello strumento di sviluppo predefinito della mia azienda. Sto usando lo stdint.h types (uint8_t, uint32_t, ecc.).Utilizzo di typecasting per rimuovere gli avvisi del compilatore gcc

Il compilatore crea avvisi ogni volta che eseguo un'assegnazione composta o anche un'aggiunta semplice. Per esempio:

uint8_t u8 = 0; 
uint16_t u16; 

// These cause warnings: 
u8 += 2; 
u8 = u16 >> 8; 

Il "metodo comune" per risolvere questo problema è quello di utilizzare calchi, come discusso here e here:

u8 = (uint8_t)(u8 + 2); 
u8 = (uint8_t)(u16 >> 8); 

Oltre a questo essere brutto, io continuo a correre in prove convincenti che il casting è generalmente una cattiva pratica.

Le mie domande:

  1. Perché è brutto da usare typecasts in questo modo?
  2. Perdo qualcosa semplicemente omettendo -Wconversion e lasciando che il compilatore esegua conversioni implicite per me?
+0

In questo caso non c'è niente di "cattivo" nel typecasting. Se non altro, mostra che hai considerato la semantica, l'aritmetica avvolgente, il troncamento, ecc. E ne sei soddisfatto. –

+0

@BrettHale, almeno il cast * afferma * di aver preso in considerazione tutte le implicazioni e di esserne soddisfatto. Anche se non l'hai fatto o no. –

+1

@BrettHale, si potrebbe mettere il cast lì se ci si preoccupa di più di chiudere il compilatore rispetto a un possibile codice errato (non fare lo scherno - succede). Potresti farlo anche se pensi di aver preso in considerazione tutte le implicazioni, ma ti sbagli. O anche se non lo sai meglio. Sono d'accordo sul fatto che il casting non è intrinsecamente, necessariamente * cattivo *, ma evitare la necessità di eseguire il cast in primo luogo è * migliore *. –

risposta

3

Il compilatore mostra potenziali problemi che dovresti prendere in considerazione di cambiare, ma non in base al cast. Il problema nel codice che si ha è in C, l'aritmetica non viene mai eseguita su un tipo che è più stretto di int: il compilatore esegue sempre una conversione implicita su int.

Così efficacemente il codice sta convertendo i tipi senza segno stretto in int, esegue l'operazione e quindi li converte nuovamente nel tipo senza segno.

Generalmente l'aritmetica con tipi stretti non è una buona idea. Usateli solo se la dimensione della memoria è un problema (di solito sarebbero strutture più grandi come gli array). Per le variabili locali, più o meno temporanee, questi tipi ristretti non hanno senso.

3

È una questione di gusti. Un cast non è mai richiesto da C quando si assegna un valore di un tipo aritmetico a un oggetto di un tipo aritmetico diverso. Alcune persone usano il cast per documentare che c'è una conversione nascosta e che lo hanno fatto apposta.

Personalmente non mi piace mettere cose in più inutile e presumo che il lettore conosce le basi del C quindi tendo ad evitare il cast (e non uso -Wconversion che non è una parte di -Wall o anche -Wextra Comunque). Si noti che in un incarico se un letterale sul lato destro non può rientrare nell'oggetto lato sinistro gcc di solito avverte (senza -Wall o -Wextra) anche se l'assegnazione non è UB.

2

Il problema con i cast è che dicono al compilatore "stai zitto, so cosa sto facendo", anche se non lo fai. Se qualcuno decide che la variabile deve essere in grado di gestire valori maggiori di 255 e cambia il tipo in uint16_t, u8 + = 2 funzionerebbe, ma u8 = (uint8_t) (u8 + 2) verrebbe interrotto. Supponendo che la variabile non sia denominata u8 ma "numberOfParagraphs", ad esempio, potrebbe trattarsi di un errore molto difficile da trovare.

Meglio utilizzare un tipo più grande in primo luogo. A meno che tu non voglia, davvero, archiviare (u8 + 2) & 0xff, nel qual caso puoi scriverlo in quel modo e memorizzarlo in una variabile più grande senza problemi.

(Personalmente vorrei un'estensione del linguaggio come

(uint8_t)u8 += 2; 

con la semantica che esprimono un valore assegnabile al proprio tipo non ha effetto e resta un lvalue durante la rimozione del avvertimento, ma esprimono un lvalue un altro tipo potrebbe essere un errore, in questo modo sarebbe più sicuro chiudere l'avviso del compilatore)