2015-10-21 30 views
7

Considerate questo codice:Il risultato delle operazioni bit a bit sui tipi di integrale firmato è ben definito?

using integer = int; // or any other fundamental integral type 
using unsigned_integer = typename std::make_unsigned<integer>::type; 
constexpr integer bits = std::numeric_limits<unsigned_integer>::digits; 
integer value = -42; // or any value 
integer mask = static_cast<integer>(1)<<static_cast<integer>(bits-1); 
bool result_and = value & mask; 
bool result_or = value | mask; 
bool result_xor = value^mask; 

mi chiedo quanto bene sono queste operazioni definite secondo lo standard. Ho la garanzia di finire con gli stessi risultati su tutte le architetture? Sono sicuro di operare sul bit di segno su tutte le architetture in cui questo bit di segno è 0 per i numeri positivi e 1 per i numeri negativi?

+0

Vedere anche [Qual è il risultato di a & b?] (Http://stackoverflow.com/q/29394518/1708801) che è strettamente correlato ma non un duplicato. –

risposta

3

I risultati di bit per bit, bit per bit o bit per bit sono attualmente sottodimensionati nello standard, in particolare il termine bitmap non viene mai definito. Abbiamo defect report 1857: Additional questions about bits che copre questo problema e dice:

La specifica delle operazioni bit per bit a 5.11 [expr.bit.and], 5.12 [expr.xor], e 5.13 [expr.or] utilizza il non definito termine "bit a bit" nel descrivere le operazioni, senza specificare se si tratta del valore o della rappresentazione oggetto che è in vista.

Parte della risoluzione di questo potrebbe essere quello di definire “bit” (che altrimenti è attualmente indefinito in C++) come valore di una determinata potenza di 2.

e la risoluzione era:

CWG ha deciso di riformulare la descrizione delle operazioni per evitare riferimenti a bit, suddividendo le maggiori domande di definire "bit" e simili per il rilascio 1943 per ulteriori considerazioni su .

Che ha provocato un consolidamento defect report 1943: Unspecified meaning of “bit”.

Il risultato dello spostamento a sinistra di un tipo firmato dipende dalla rappresentazione sottostante. Possiamo vedere questo dal defect report 1457: Undefined behavior in left-shift che ha reso ben definito di spostamento a sinistra nel bit di segno e dice:

L'attuale formulazione di 5,8 [expr.shift] paragrafo 2 rende indefinita comportamento per creare il più- intero negativo di un determinato tipo dal architetture sinistra-shifting un (firmato) 1 nel bit di segno, anche se questo non è insolitamente fatto e funziona correttamente sulla maggior parte dei (complemento a due):

... se E1 ha un tipo firmato e non negativo va lue, e E1 ⨯ 2E2 è rappresentabile nel tipo di risultato, quindi questo è il valore risultante; in caso contrario, il comportamento non è definito.

Come risultato, questa tecnica non può essere utilizzata in un'espressione costante, che interromperà una quantità significativa di codice.

Notando l'enfasi sulla dichiarazione funziona correttamente sulla maggior parte dei (complemento a due) architetture. Quindi dipende dalla rappresentazione sottostante per esempio il doppio complemento.

1

riguardo sinistra e operatori spostamento a destra, dal C++ parte standard 5.8:

Il comportamento è indefinito se l'operando destro è negativo, o maggiore o uguale alla lunghezza in bit della promossa sinistra operando.

poi si dice che l'operatore spostamento a sinistra E1 < < E2 si traduce in un comportamento indefinito, quando tutte le seguenti condizioni:

  • L'operando di sinistra ha un tipo di firma.
  • O l'operando di sinistra ha un valore negativo o ha un valore non negativo tale che E1 × 2^E2 non è rappresentabile nel tipo risultante.

Anche per l'operatore di spostamento a destra E1 >> E2, il comportamento è dipendente dall'implementazione se l'operando di sinistra ha un tipo firmato e un valore negativo.

Gli operatori AND, XOR e OR bit a bit sono ben definiti per tutti i tipi di integrale. Questo è specificato nelle sezioni 5.11, 5.12 e 5.13, rispettivamente.

Tuttavia, si noti che la rappresentazione di valori interi firmati può essere Complemento a due, Complemento o grandezza firmata. La maggior parte dei compilatori usa comunque la rappresentazione del complemento a due. Questi includono gcc, VC++, icl e Clang.

1

Operatori &, | e ^ sono bit a bit, e trattare con singoli bit, in modo da faranno esattamente quello che scritto: applicare la mask.

Spostamento a sinistra L'operatore << è un po 'più complicato. Condurrà a comportamento indefinito se si sposta il valore negativo o se si sposta 1 per firmare la posizione del bit o oltre.

static_cast<integer>(1)<<static_cast<integer>(bits-1);

Sembra si passa 1 firmare posizione po 'là, ed è un comportamento indefinito.