Sök…


Anmärkningar

Bitskiftningsoperationer är inte bärbara över alla processorarkitekturer, olika processorer kan ha olika bitbredd. Med andra ord, om du skrev

int a = ~0;
int b = a << 1;

Detta värde skulle vara annorlunda på en 64-bitars maskin kontra på en 32-bitars maskin, eller från en x86-baserad processor till en PIC-baserad processor.

Endian-ness behöver inte beaktas för själva lite kloka operationer, det vill säga rätt skift ( >> ) kommer att flytta bitarna mot den minst betydande biten och en XOR kommer att utföra en exklusiv eller på bitarna. Endian-ness behöver bara beaktas med själva uppgifterna, det vill säga om endian-ness är ett problem för din ansökan är det ett problem oavsett lite kloka funktioner.

& - bitvis OCH

int a = 6;     // 0110b  (0x06)
int b = 10;    // 1010b  (0x0A)
int c = a & b; // 0010b  (0x02)

std::cout << "a = " << a << ", b = " << b << ", c = " << c << std::endl;

Produktion

a = 6, b = 10, c = 2

Varför

Lite klok AND arbetar på bitnivån och använder följande booleska sanningstabell:

TRUE  AND TRUE  = TRUE
TRUE  AND FALSE = FALSE
FALSE AND FALSE = FALSE

När det binära värdet för a ( 0110 ) och det binära värdet för b ( 1010 ) AND 'redigeras tillsammans får vi det binära värdet 0010 :

int a = 0 1 1 0
int b = 1 0 1 0 &
        ---------
int c = 0 0 1 0

Den bitmässiga OCH ändrar inte värdet på de ursprungliga värdena såvida inte specifikt tilldelats att använda den bitmässiga tilldelningssammansättningsoperatören &= :

int a = 5;  // 0101b  (0x05)
a &= 10;    // a = 0101b & 1010b

| - bitvis ELLER

int a = 5;     // 0101b  (0x05)
int b = 12;    // 1100b  (0x0C)
int c = a | b; // 1101b  (0x0D)

std::cout << "a = " << a << ", b = " << b << ", c = " << c << std::endl;

Produktion

a = 5, b = 12, c = 13

Varför

Lite klok OR fungerar på bitnivån och använder följande booleska sanningstabell:

true OR true = true
true OR false = true
false OR false = false

När det binära värdet för a ( 0101 ) och det binära värdet för b ( 1100 ) OR redigeras tillsammans får vi det binära värdet 1101 :

int a = 0 1 0 1
int b = 1 1 0 0 |
        ---------
int c = 1 1 0 1

Den bitmässiga ELLER ändrar inte värdet på de ursprungliga värdena såvida inte specifikt tilldelats att använda den bitvisa tilldelningens sammansatta operatör |= :

int a = 5;  // 0101b  (0x05)
a |= 12;    // a = 0101b | 1101b

^ - bitvis XOR (exklusiv ELLER)

int a = 5;     // 0101b  (0x05)
int b = 9;     // 1001b  (0x09)
int c = a ^ b; // 1100b  (0x0C)

std::cout << "a = " << a << ", b = " << b << ", c = " << c << std::endl;

Produktion

a = 5, b = 9, c = 12

Varför

En lite klok XOR (exklusiv eller) fungerar på bitnivån och använder följande booleska sanningsbord:

true OR true = false
true OR false = true
false OR false = false

Lägg märke till att med en XOR-operation true OR true = false där som med operationer true AND/OR true = true , följaktligen XOR-operationens exklusiva karaktär.

Om detta används, när det binära värdet för a ( 0101 ) och det binära värdet för b ( 1001 ) är XOR 'tillsammans får vi det binära värdet 1100 :

int a = 0 1 0 1
int b = 1 0 0 1 ^
        ---------
int c = 1 1 0 0

Den bitvisa XOR ändrar inte värdet på de ursprungliga värdena såvida inte specifikt tilldelats att använda den bitvisa tilldelningen sammansatta operatören ^= :

int a = 5;  // 0101b  (0x05)
a ^= 9;    // a = 0101b ^ 1001b

Den bitvisa XOR kan användas på många sätt och används ofta vid bitmaskoperationer för kryptering och komprimering.

Obs: Följande exempel visas ofta som ett exempel på ett fint trick. Men bör inte användas i produktionskod (det finns bättre sätt std::swap() att uppnå samma resultat).

Du kan också använda en XOR-operation för att byta två variabler utan en tillfällig:

int a = 42;
int b = 64;

// XOR swap
a ^= b;
b ^= a;
a ^= b;

std::cout << "a = " << a << ", b = " << b << "\n";

För att producera detta måste du lägga till en check för att se till att den kan användas.

void doXORSwap(int& a, int& b)
{
    // Need to add a check to make sure you are not swapping the same
    // variable with itself. Otherwise it will zero the value.
    if (&a != &b)
    {
        // XOR swap
        a ^= b;
        b ^= a;
        a ^= b;
    }
}

Så även om det ser ut som ett fint trick isolerat, är det inte användbart i riktig kod. xor är inte en baslogisk operation, utan en kombination av andra: a ^ c = ~ (a & c) & (a | c)

även i 2015+ kompilatorvariabler kan tilldelas som binär:

int cn=0b0111;

~ - bitvis INTE (unikt komplement)

unsigned char a = 234;  // 1110 1010b  (0xEA)
unsigned char b = ~a;   // 0001 0101b  (0x15)

std::cout << "a = " << static_cast<int>(a) <<
             ", b = " << static_cast<int>(b) << std::endl;

Produktion

a = 234, b = 21

Varför

Lite klokt NOT (unikt komplement) fungerar på bitnivån och vänder helt enkelt varje bit. Om det är ett 1 , ändras det till ett 0 , om det är ett 0 , ändras det till ett 1 . Den lite kloka INTE har samma effekt som XOR att sätta ett värde mot maxvärdet för en specifik typ:

unsigned char a = 234;  // 1110 1010b  (0xEA)
unsigned char b = ~a;   // 0001 0101b  (0x15)
unsigned char c = a ^ ~0;

Det lite kloka INTE kan också vara ett bekvämt sätt att kontrollera det maximala värdet för en specifik integraltyp:

unsigned int i = ~0;
unsigned char c = ~0;

std::cout << "max uint = " << i << std::endl <<
             "max uchar = " << static_cast<short>(c) << std::endl;

Det lite kloka ändrar INTE inte värdet på det ursprungliga värdet och har inte en sammansatt tilldelningsoperatör, så du kan inte göra a ~= 10 till exempel.

Det lite kloka INTE ( ~ ) bör inte förväxlas med det logiska INTE ( ! ); där lite klokt INTE kommer att vända varje bit, kommer en logisk INTE att använda hela värdet för att utföra sin funktion på, med andra ord (!1) != (~1)

<< - vänster skift

int a = 1;      // 0001b
int b = a << 1; // 0010b

std::cout << "a = " << a << ", b = " << b << std::endl;

Produktion

a = 1, b = 2

Varför

Den vänstra bitvisa växlingen kommer att förskjuta bitarna i det vänstra värdet ( a ) antalet som anges till höger ( 1 ), väsentligen vadderar de minst betydande bitarna med 0: er, så att värdet på 5 (binär 0000 0101 ) 0000 0101 till vänster 4 gånger (t.ex. 5 << 4 ) ger värdet 80 (binär 0101 0000 ). Du kanske noterar att att flytta ett värde till vänster 1 gång också är detsamma som att multiplicera värdet med 2, exempel:

int a = 7;
while (a < 200) {
    std::cout << "a = " << a << std::endl;
    a <<= 1;
}

a = 7;
while (a < 200) {
    std::cout << "a = " << a << std::endl;
    a *= 2;
}

Men det bör noteras att vänsterväxlingsoperationen förskjuter alla bitar till vänster, inklusive teckenbiten, exempel:

int a = 2147483647; // 0111 1111 1111 1111 1111 1111 1111 1111
int b = a << 1;     // 1111 1111 1111 1111 1111 1111 1111 1110

std::cout << "a = " << a << ", b = " << b << std::endl;

Möjlig utgång: a = 2147483647, b = -2

Medan vissa kompilatorer kommer att ge resultat som verkar förväntat, bör det noteras att om du lämnar skiftande ett signerat nummer så att teckenbiten påverkas är resultatet odefinierat . Det är också odefinierat om antalet bitar du vill växla med är ett negativt antal eller är större än antalet bitar som typen till vänster kan innehålla, exempel:

int a = 1;
int b = a << -1;  // undefined behavior
char c = a << 20; // undefined behavior

Den bitvisa vänsterförskjutningen ändrar inte värdet på de ursprungliga värdena såvida inte specifikt tilldelats att använda den bitvisa tilldelningen sammansatta operatören <<= :

int a = 5;  // 0101b
a <<= 1;    // a = a << 1;

>> - höger skift

int a = 2;      // 0010b
int b = a >> 1; // 0001b

std::cout << "a = " << a << ", b = " << b << std::endl;

Produktion

a = 2, b = 1

Varför

Den högra bitvisa växlingen förskjuter bitarna i det vänstra värdet ( a ) numret som anges till höger ( 1 ); Det bör noteras att även om driften av en högerväxling är standard, är vad som händer med bitarna av en högerförskjutning på ett undertecknat negativt nummer implementeringsdefinierat och därför kan det inte garanteras att det är portabelt, exempel:

int a = -2;    
int b = a >> 1; // the value of b will be depend on the compiler

Det definieras också om antalet bitar du vill växla med är ett negativt antal, exempel:

int a = 1;
int b = a >> -1;  // undefined behavior

Den bitmässiga höger växlingen ändrar inte värdet på de ursprungliga värdena såvida inte specifikt tilldelats att använda den bitvisa tilldelningen sammansatta operatören >>= :

int a = 2;  // 0010b
a >>= 1;    // a = a >> 1;


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow