Scambio bit aritmetico su un numero intero con segno

Sto cercando di capire come funzionano esattamente gli operatori aritmetici di spostamento dei bit in C e come influenzerà gli interi firmati a 32 bit.

Per semplificare le cose, diciamo che lavoriamo con un byte (8 bit):

x = 1101.0101 MSB[ 1101.0101 ]LSB 

Leggendo altri post su Stack Overflow e alcuni siti Web, ho scoperto che: << si sposterà verso MSB (a sinistra, nel mio caso) e riempirà “vuoti” bit LSB con 0 secondi.

E >> si sposterà verso LSB (a destra, nel mio caso) e riempirà i bit “vuoti” con MS bit

Quindi, x = x << 7 comporterà lo spostamento di LSB su MSB e l’impostazione di tutto su 0s.

 1000.0000 

Ora, diciamo che vorrei >> 7 , ultimo risultato. Ciò risulterebbe in [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; //111111111......11 (Everything is filled with 1s !!!!!) 

Perché?

Il giusto spostamento di un numero firmato negativo ha un comportamento definito dall’implementazione.

Se i tuoi 8 bit sono pensati per rappresentare un valore a 8 bit con segno (dato che stai parlando di un “intero con segno a 32 bit” prima di passare ad esempi a 8 bit) allora hai un numero negativo. Se lo si sposta a destra, è ansible riempire i bit “vuoti” con il MSB originale (ovvero eseguire l’estensione del segno) o potrebbe spostarsi in zero, a seconda della piattaforma e / o del compilatore.

(Il 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 numero inizia o è negativo, o 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).

(Un comportamento indefinito significa che potrebbe accadere qualcosa.)


Le stesse operazioni su valori senza segno sono ben definite in entrambi i casi: i bit “vuoti” saranno riempiti con 0.

Le operazioni di spostamento bit a bit non sono definite per i 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 per ‘>>’

6.5.7 / 5 […] Se E1 ha un tipo firmato e un valore negativo, il valore risultante è definito dall’implementazione.

È una perdita 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, il compilatore sul proprio computer con il proprio parametri specifici per le linee di comunicazione).

Potrebbe non funzionare nemmeno per una versione più vecchia 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 a sinistra di 1 ( expression << 1 ) è lo stesso di multispazio dell'espressione per 2 (l'espressione fornita * 2 non ha un overflow) e l'effetto di spostamento a destra di 1 ( expression >> 1 ) equivale a dividere per 2.

Come altri hanno detto, lo spostamento del valore negativo è definito dall’implementazione.

La maggior parte delle implementazioni trattano lo spostamento a destra firmato come floor (x / 2 N ) riempiendo i bit spostati usando 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 dal lato della macchina, la maggior parte delle implementazioni ha due tipi di istruzioni shift-right:

  1. Uno spostamento “aritmetico” a destra (spesso con ASR mnemonico o SRA) che funziona come ho spiegato.

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

La maggior parte dei compilatori utilizza prima i tipi firmati e la seconda quelli non firmati. Solo per comodità

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.

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

qui x valore implementa il complimento di 1.

quindi l’ultima x è -32768