Conversione aritmetica normale & # 8212; un migliore insieme di regole?
-
08-07-2019 - |
Domanda
Considera il seguente codice:
void f(byte x) {print("byte");}
void f(short x) {print("short");}
void f(int x) {print("int");}
void main() {
byte b1, b2;
short s1, s2;
f(b1 + b2); // byte + byte = int
f(s1 + s2); // short + short = int
}
In C ++, C #, D e Java, entrambe le chiamate di funzione si risolvono in " int " sovraccarichi ... Capisco già questo è " nelle specifiche " ;, ma perché le lingue sono progettate in questo modo? Sto cercando un motivo più profondo.
Per me ha senso che il risultato sia il tipo più piccolo in grado di rappresentare tutti i possibili valori di entrambi gli operandi , ad esempio:
byte + byte --> byte
sbyte + sbyte --> sbyte
byte + sbyte --> short
short + short --> short
ushort + ushort --> ushort
short + ushort --> int
// etc...
Ciò eliminerebbe il codice scomodo come short s3 = (short) (s1 + s2)
, così come l'IMO sarebbe molto più intuitivo e più facile da capire.
È un'eredità lasciata dai tempi di C o ci sono ragioni migliori per l'attuale comportamento?
Soluzione
Citato da questo post sul blog MSDN :
byte b = 32; byte c = 240; int i = b + c; // cosa sono io?
In questo mondo fantastico, il valore di i sarebbe 16! Perché? Perché i due gli operandi per l'operatore + sono entrambi byte, quindi la somma "b + c" è calcolato come un byte, che risulta in 16 a causa di overflow intero. (E, come ho notato in precedenza, l'overflow dei numeri interi è il nuovo vettore di attacco di sicurezza.)
Allo stesso modo,
int j = -b;
comporterebbe j con il valore 224 e non -32, per lo stesso motivo.
È davvero quello che vuoi?
...
Quindi, non importa come lo tagli, lo sei dovrà inserire fastidiosi getta. Può anche avere la lingua err dal lato della sicurezza (costringendoti per inserire i calchi dove conosci che l'overflow non è un problema) rispetto a errare dal lato del silenzio (dove tu potrebbe non notare i cast mancanti fino al il tuo reparto buste paga ti chiede perché i loro libri non si sommano alla fine di il mese).
Inoltre, vale la pena notare che aggiungere in questi cast significa solo digitare in più e niente di più. Una volta che JIT (o forse il compilatore statico stesso) riduce l'operazione aritmetica a un'istruzione di base del processore, non c'è nulla di intelligente in corso - è solo se il numero viene trattato come un int
o byte
.
Questa è una buona domanda, tuttavia ... per niente ovvia. Spero che ora le ragioni siano chiare per te.
Altri suggerimenti
Un migliore insieme di regole IMHO, se si prevedesse che gli operatori di spostamento potrebbero essere utilizzati solo con valori di spostamento costanti (utilizzare le funzioni di spostamento per importi di spostamento variabili), sarebbe che i risultati di qualsiasi espressione aritmetica dovrebbero sempre valutare come se sono stati elaborati con il tipo di firma o non firmata più grande possibile, a condizione che uno dei due potesse essere staticamente garantito per fornire risultati corretti (si applicherebbero regole leggermente complicate nei casi in cui il tipo con firma più grande potrebbe non essere sufficiente). A condizione che gli operandi a turni possano essere solo costanti, si potrebbe determinare abbastanza facilmente in fase di compilazione quale potrebbe essere il valore più significativo di qualsiasi operando, quindi non vedo alcuna buona ragione per i compilatori di non vedere come viene utilizzato il risultato di un operatore nel decidere sull'attuazione dell'operatore.