2013-01-07 7 views
12

Quando si aggiunge uno int32 a un native int a 64 bit, il CLR sign-estendere o estendere a zero il numero intero a 32 bit? E soprattutto: sulla base di quali informazioni fa questa scelta?Risultato dell'aggiunta di un int32 a un nativo a 64 bit int?


Sto scrivendo un compilatore .NET e hanno letto la specifica ECMA accuratamente, ma non riusciva a trovare una risposta.

La CLI supporta solo un sottoinsieme di questi tipi nelle sue operazioni su valori memorizzati sul suo stack di valutazione: int32, int64 e native int.
- ECMA 335, Sezione I 12.1: supportati i tipi di dati

Poiché i valori nello stack di valutazione non hanno informazioni sulla loro signedness, istruzioni per i quali il signedness degli operandi importa avere due varianti: una per firmato e uno per interi senza segno. Le istruzioni add, sub e mul (quelle che non controllano l'overflow) non devono preoccuparsi della firma degli operandi purché gli operandi abbiano le stesse dimensioni e pertanto abbiano solo una singola variante. Tuttavia, gli operandi non sono sempre le stesse dimensioni ...

ECMA 335, Sezione III 1.5: Operando tipo di tabella si rileva che una int32 e native int può essere aggiunto, sottratto, moltiplicato e diviso. Il risultato è ancora un native int. Su un sistema a 64 bit, uno native int ha una larghezza di 64 bit.

ldc.i4.0   // Load int32 0 
conv.i    // Convert to (64-bit) native int 
ldc.i4.m1   // Load int32 -1 
add     // Add native int 0 and int32 0xFFFFFFFF together 

Quindi quale sarebbe il risultato qui? Si noti che, in base alle specifiche, il runtime non deve tracciare i tipi esatti o la firma dei valori nello stack: conosce solo int32, int64 e native int (e alcuni altri che non sono rilevanti qui).


Immagino che IntPtr e UIntPtr aritmetica, dal momento che è rappresentato internamente come interi nativi, potrebbe anche utilizzare questo tipo di aggiunta. Tuttavia, ILSpy mostra che l'aggiunta di uno IntPtr e uno Int32 in C# chiama l'operatore + sovraccarico sulla classe IntPtr, che accetta solo un argomento firmato Int32.

Facendolo direttamente in CIL (utilizzando l'istruzione add) indica anche che il numero intero viene interpretato come firmato. Dovrebbe anche essere stato implementato in Mono, ma non sono riuscito a trovare alcun riferimento per le mie scoperte.

+0

Il segno per il valore promosso non verrà catturato. Vedi queste informazioni per possibili soluzioni (è per Mac ma ciò non dovrebbe importare in questo caso): https://developer.apple.com/library/mac/#documentation/Darwin/Conceptual/64bitPorting/MakingCode64-BitClean/MakingCode64- BitClean.html – K3N

risposta

5

La firma non ha importanza quando si aggiungono due valori dello stesso bit. Ad esempio, l'aggiunta di 32-bit -10 (0xfffffff6) a 32-bit 10 (0x0000000a) restituirà correttamente 0. A causa di ciò, c'è solo un'istruzione add nel CIL (Common Instruction Language).

Tuttavia, quando si aggiungono due valori di bit di bit diverso, la firma ha importanza. Ad esempio, l'aggiunta di 32-bit da -10 a 64-bit 10 può comportare 4294967296 (0x100000000) quando viene eseguito senza segno e 0 al momento della firma.

Il add istruzione CIL permette l'aggiunta di un intero nativo e un intero a 32 bit. Il numero intero nativo può essere a 64 bit (su un sistema a 64 bit). I test rivelano che add considera il numero intero a 32 bit come un intero con segno e il segno lo estende.This is not always correct e può essere considerato a bug. Microsoft non ha intenzione di risolverlo.

Poiché il controllo di overflow dipende dal fatto che gli operandi siano considerati non firmati o firmati, esistono due varianti di add.ovf: add.ovf (firmato) e add.ovf.un (senza segno). Tuttavia, anche queste varianti firmano correttamente l'estensione zero estendono l'operando più piccolo quando si aggiunge un intero a 32 bit a un intero nativo.

Quindi aggiungere un intero nativo e un numero intero a 32 bit senza segno può produrre risultati diversi a seconda dell'impostazione di controllo di overflow di C#. Apparentemente il fatto che non riuscissi a capirlo è il risultato di un bug o di una svista nel design del linguaggio CIL.

2

Sei in un territorio inesplorato qui, non conosco alcun linguaggio .NET che in realtà lo consenta. Il loro correttore di sintassi rifiuta qualsiasi codice che cerchi di farlo. Anche l'aggiunta di due input nativi viene rifiutata. Alla fine spetta al jitter generare il codice macchina per esso. Se vuoi sapere cosa succede, fai un esperimento. Assicurati di testare almeno il jitter x86 e x64.

Data la semantica ef fi ciente e la possibilità molto reale che un cambiamento di jitter futuro possa infrangere le vostre ipotesi, raccomando vivamente di rifiutarlo anche nella vostra lingua.Non è molto utile e una semplice soluzione alternativa a (lunga) e il risultato (IntPtr) ha una semantica ben definita. Che di per sé è un modo per ottenere un comportamento prevedibile nel proprio generatore di codice.

+0

Ho aggiunto alcune informazioni al post: C# utilizza l'operatore di overload aggiunto quando aggiunge 'IntPtr' a' Int32'. In CIL, l'istruzione 'add' sembra interpretare' Int32' come firmata. Tuttavia, non so perché. – Virtlink

Problemi correlati