Sto scrivendo un compilatore che usa l'antica strategia di usare un compilatore C come back-end, e sto cercando di capire esattamente come gestire il segno intero.
Sto usando gli interi di parola macchina come default (traducendo in intptr_t
e uintptr_t
nella C generata), e mentre per me preferirei rendere il default senza segno, probabilmente non ho molta scelta riguardo alla sua firma solo perché tale aspettativa è così radicata.
Sto definendo il risultato dell'overflow di interi per essere wraparound (almeno per impostazione predefinita, potresti aggiungere un'opzione per lanciare un'eccezione in seguito), ma in C, l'overflow di interi con segno è un comportamento indefinito, quindi non posso emettere solo codice che esegue l'aritmetica dell'intero con segno. Mi sembra ci siano due opzioni:
-
Emetti interi con segno, ma converti in unsigned per tutte le operazioni aritmetiche eccetto la divisione e il right shift (questi sono gli unici dove conta la differenza, e anche gli unici che non possono overflow - edit: ad eccezione di
INT_MIN
/ -1; stavo considerando che nella stessa categoria della divisione per zero, ma ovviamente si tratta in senso stretto di un overflow). -
Emetti interi senza segno, ma converti in segno per divisione (resistendo alla tentazione di fare divisione dei numeri negativi comportamento indefinito), spostamento a destra e confronto diverso dall'uguaglianza.
-
Emetti interi con segno, usa
-fwrapv
quando usi GCC come backend, e spera che altri compilatori C non traggano vantaggio dall'overflow firmato indefinito, o forniscano un interruttore per disabilitare tali ottimizzazioni.
La terza opzione funziona (ad es. ci sono compilatori C in cui non è possibile eseguire il wrap overflow con firma)? In caso contrario, quale delle due prime probabilità implicherà meno codice e opportunità di errore? C'è qualcosa che mi manca?