2010-10-24 17 views
42

Sto cercando di capire come funzionano esattamente gli operatori di spostamento bit aritmetico in C, e come influenzerà gli interi firmati a 32 bit.Scambio bit aritmetico su un numero intero con segno

Per rendere le cose semplici, diciamo che lavoriamo all'interno di un byte (8 bit):

x = 1101.0101 
MSB[ 1101.0101 ]LSB 

Leggendo altri messaggi su Stack Overflow e alcuni siti web, ho scoperto che: << si sposterà verso MSB (per a sinistra, nel mio caso), e riempire "vuoti" bit LSB con 0 s.

E >> si sposterà verso LSB (a destra, nel mio caso) e riempire i bit "vuoti" con SM bit

Quindi, x = x << 7 si tradurrà in movimento LSB a MSB, e l'impostazione di tutto per 0s.

1000.0000 

Ora, diciamo che vorrei >> 7, ultimo risultato. Ciò comporterebbe [0000.0010]? Ho ragione?

Ho ragione riguardo alle mie ipotesi sugli operatori di turno?

Ho appena provato sulla mia macchina, **

int x = 1; //000000000......01 

x = x << 31; //100000000......00 

x = x >> 31; //111111111......11 (Everything is filled with 1s !!!!!) 

Perché?

+3

possibile duplicato del [operatore Spostamento in C] (http://stackoverflow.com/questions/7622/shift-operator-in-c) –

+5

"Perché?"Perché ** la tua implementazione ** lo dice. Controlla la documentazione: ** deve ** definire il comportamento del giusto spostamento di un valore negativo (o non hai un compilatore C) – pmg

+0

@ pseudonym27 che devi trovare in documentazione – newprint

risposta

47

Il passaggio a destra di un numero con segno negativo ha un comportamento definito dall'implementazione.

Se i tuoi 8 bit intendono rappresentare un valore a 8 bit con segno (poiché stai parlando di un "intero con segno a 32 bit" prima di passare agli esempi a 8 bit), allora hai un numero negativo. Se lo si sposta a destra, è possibile riempire i bit "vuoti" con il MSB originale (ovvero eseguire l'estensione del segno) o potrebbe spostarsi in zeri, a seconda della piattaforma e/o del compilatore.

(comportamento definito dall'implementazione significa che il compilatore farà qualcosa di sensato, ma in un modo dipendente dalla piattaforma, la documentazione del compilatore dovrebbe dirti cosa.)


uno spostamento a sinistra, se il il numero inizia o è negativo, oppure l'operazione di spostamento sposterebbe un 1 verso o oltre il bit del segno, ha un comportamento indefinito (come la maggior parte delle operazioni sui valori firmati che causano un overflow).

(comportamento indefinito significa che nulla potrebbe accadere.)


Le stesse operazioni su senza segno valori sono ben definiti in entrambi i casi: i bit "vuoti" verranno riempiti con 0.

+1

Va detto che il giusto passaggio con la semantica standard portatile è anche noto come divisione di un power-of-two letterale. genererà spostamenti aritmetici per tali divisioni, r esulting in codice veloce che firma l'estensione come desiderato. –

+2

@KubaOber: gli standard moderni richiedono che 'x/2' si comportino diversamente da uno spostamento verso destra nel caso in cui' x' sia un numero dispari negativo. Un normale spostamento aritmetico verso destra eseguirà la divisione floored (quindi nei casi che non superano '(n + d)/d == (n/d) + 1', ma la divisione è necessaria per utilizzare la divisione troncata, impedendo così ai compilatori di – supercat

+0

@KubaOber: Va notato che lo spostamento a sinistra di un valore con segno utilizzato per essere un multiplo con la potenza di due, ma i compilatori più recenti sembrano avere il supporto deprecato per lo spostamento a sinistra di numeri negativi. – supercat

32

operazioni spostamento bit a bit non sono definiti per valori negativi

per '< <'

6.5.7/4 [...] Se E1 ha un tipo firmato e un valore non negativo e E1 × 2 E2 è rappresentabile nel tipo di risultato, allora questo è il valore risultante; in caso contrario, il comportamento non è definito.

e '>>'

6.5.7/5 [...] Se E1 ha un tipo firmato e un valore negativo, il valore risultante è specifica di esecuzione definito.

È uno spreco di tempo studiare il comportamento di queste operazioni sui numeri firmati su un'implementazione specifica, perché non si ha alcuna garanzia che funzionerà allo stesso modo su qualsiasi altra implementazione (un'implementazione è, ad esempio, compilatore sul tuo computer con i tuoi specifici parametri della linea di comando).

Potrebbe non funzionare nemmeno per una versione precedente o più recente dello stesso compilatore. Il compilatore potrebbe anche definire quei bit come casuali o non definiti. Ciò significherebbe che la stessa sequenza di codice potrebbe produrre risultati completamente diversi se usata attraverso le tue fonti o anche dipendere da cose come l'ottimizzazione dell'assemblaggio o l'utilizzo di altri registri. Se incapsulato in una funzione, potrebbe non produrre nemmeno lo stesso risultato in quei bit su due chiamate consecutive con gli stessi argomenti.

Considerando solo valori non negativi, l'effetto di spostamento sinistra di 1 (expression << 1) è la stessa multpliying l'espressione da 2 (espressione disponibile * 2 non trabocchi) e l'effetto di destra spostamento da 1 (expression >> 1) equivale a dividere per 2.

5

Come altri, lo spostamento del valore negativo è definito dall'implementazione.

La maggior parte delle implementazioni trattano lo spostamento a destra con segno come pavimento (x/2 N) riempiendo i bit spostati con il bit di segno. In pratica è molto conveniente, poiché questa operazione è così comune. D'altra parte se si sposta a destra numero intero senza segno, spostato in bit verrà azzerato.

Guardando da lato della macchina, la maggior parte delle implementazioni hanno due tipi di operazioni di scorrimento a destra:

  1. Un diritto 'aritmetica' turno (spesso con mnemonico ASR o SRA) che lavora come me spiegato.

  2. Uno spostamento 'logico' a destra (che ha mnemonico LSR o SRL o SR) che funziona come ci si aspetta.

Molti compilatori utilizzano prima i tipi firmati e il secondo quelli non firmati. Solo per comodità

0

Nel compilatore a 32 bit

x = x >> 31;

qui x è il numero intero con segno in modo che il 32 ° bit sia un bit di segno.

valore x finale è 100000 ... 000. e il 32 bit indica il valore -ive.

qui x valore implementare al complimento di 1.

allora x finale è -32768

Problemi correlati