수색…
비고
비트 시프트 연산은 모든 프로세서 아키텍처에서 이식 가능하지 않으며, 서로 다른 프로세서가 서로 다른 비트 폭을 가질 수 있습니다. 다른 말로하면, 당신이 썼다면
int a = ~0;
int b = a << 1;
이 값은 64 비트 시스템과 32 비트 시스템에서 다를 수 있으며 x86 기반 프로세서에서 PIC 기반 프로세서로 달라질 수 있습니다.
Endian-ness는 비트 단위 연산 자체에서 고려 될 필요가 없습니다. 즉, 오른쪽 시프트 ( >>
)는 비트를 최하위 비트쪽으로 이동시키고 XOR은 배타적 또는 비트를 수행합니다. 엔디안은 데이터 그 자체 만 고려해야합니다. 즉, 엔디안이 응용 프로그램에 문제가되는 경우 비트 연산과 상관없이 문제가됩니다.
& - 비트 AND
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;
산출
a = 6, b = 10, c = 2
왜
현명한 비트 AND
비트 레벨에서 작동하며 다음과 같은 부울 진실 테이블을 사용합니다 :
TRUE AND TRUE = TRUE
TRUE AND FALSE = FALSE
FALSE AND FALSE = FALSE
a
( 0110
)에 대한 이진 값과 b
( 1010
)에 대한 이진 값을 AND
연산하면 0010
의 이진 값을 얻습니다.
int a = 0 1 1 0
int b = 1 0 1 0 &
---------
int c = 0 0 1 0
비트 현명한 할당 연산자 &=
를 사용하여 특별히 지정하지 않는 한 비트 현명한 AND는 원래 값의 값을 변경하지 않습니다.
int a = 5; // 0101b (0x05)
a &= 10; // a = 0101b & 1010b
| - 비트 OR
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;
산출
a = 5, b = 12, c = 13
왜
비트 단위 OR
은 비트 수준에서 작동하며 다음 부울 진리표를 사용합니다.
true OR true = true
true OR false = true
false OR false = false
a
( 0101
)에 대한 이진 값과 b
( 1100
)에 대한 이진 값을 OR
연산하면 이진 값 1101
.
int a = 0 1 0 1
int b = 1 1 0 0 |
---------
int c = 1 1 0 1
비트 현명한 할당 연산자 연산자 인 |=
을 사용하여 명시 적으로 할당하지 않는 한 비트 단위 OR은 원래 값의 값을 변경하지 않습니다.
int a = 5; // 0101b (0x05)
a |= 12; // a = 0101b | 1101b
^ - 비트 XOR (배타적 논리합)
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;
산출
a = 5, b = 9, c = 12
왜
비트 단위 XOR
(배타적 XOR
)은 비트 수준에서 작동하며 다음 부울 진리표를 사용합니다.
true OR true = false
true OR false = true
false OR false = false
XOR 연산을 사용하면 true OR true = false
가 true AND/OR true = true
연산과 true AND/OR true = true
이므로 배타적 논리합 연산이 true AND/OR true = true
합니다.
이를 사용하여 a
( 0101
)에 대한 이진 값과 b
( 1001
)에 대한 이진 값을 XOR
할 때 이진 값 1100
얻습니다.
int a = 0 1 0 1
int b = 1 0 0 1 ^
---------
int c = 1 1 0 0
비트 현명한 배정 연산자 ^=
를 사용하여 특별히 지정하지 않는 한 비트 현명한 XOR은 원래 값의 값을 변경하지 않습니다.
int a = 5; // 0101b (0x05)
a ^= 9; // a = 0101b ^ 1001b
비트 방식의 XOR은 다양한 방식으로 활용 될 수 있으며 암호화 및 압축을 위해 비트 마스크 연산에 종종 사용됩니다.
참고 : 다음 예제는 좋은 트릭의 예로 자주 표시됩니다. 그러나 프로덕션 코드에는 사용하면 안됩니다 std::swap()
같은 결과를 얻으려면 std::swap()
이 더 좋습니다).
또한 XOR 연산을 사용하여 임시없이 두 변수를 스왑 할 수 있습니다.
int a = 42;
int b = 64;
// XOR swap
a ^= b;
b ^= a;
a ^= b;
std::cout << "a = " << a << ", b = " << b << "\n";
이것을 생산하려면 수표를 사용하여 사용할 수 있는지 확인해야합니다.
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;
}
}
따라서 고립 된 멋진 트릭처럼 보일지라도 실제 코드에서는 유용하지 않습니다. xor는 기본 논리 연산이 아니라 다른 연산자의 조합입니다. a ^ c = ~ (a & c) & (a | c)
또한 2015+ 컴파일러 변수는 바이너리로 할당 될 수 있습니다 :
int cn=0b0111;
~ ~ 비트 NOT (단항)
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;
산출
a = 234, b = 21
왜
조금 현명한 NOT
(unary complement)은 비트 레벨에서 작동하고 각 비트를 단순히 플립합니다. 그것이라면 1
,으로 바뀌 0
은 A의 경우, 0
, 그것으로 바뀌 1
. 비트 현명한 NOT은 특정 유형의 최대 값에 대해 값을 배타적으로 비교하는 것과 동일한 효과를냅니다.
unsigned char a = 234; // 1110 1010b (0xEA)
unsigned char b = ~a; // 0001 0101b (0x15)
unsigned char c = a ^ ~0;
비트 현명한 NOT은 또한 특정 적분 유형에 대한 최대 값을 확인하는 편리한 방법 일 수 있습니다.
unsigned int i = ~0;
unsigned char c = ~0;
std::cout << "max uint = " << i << std::endl <<
"max uchar = " << static_cast<short>(c) << std::endl;
비트 현명한 NOT은 원래 값의 값을 변경하지 않고 복합 대입 연산자를 가지지 않으므로 a ~= 10
과 같이 할 수 없습니다.
비트 현명 NOT ( ~
)을 논리적 NOT ( !
)과 혼동해서는 안됩니다. 조금 현명한 NOT은 각 비트를 뒤집을 것이고, 논리 NOT은 전체 값을 사용하여 작업을 수행합니다 (!1) != (~1)
즉, (!1) != (~1)
<< - 왼쪽 시프트
int a = 1; // 0001b
int b = a << 1; // 0010b
std::cout << "a = " << a << ", b = " << b << std::endl;
산출
a = 1, b = 2
왜
왼쪽 비트 현명한 이동은 왼쪽 값 ( a
)의 비트를 오른쪽 ( 1
)에 지정된 숫자로 이동시켜 기본적으로 최하위 비트를 0으로 채우므로 값 5
(이진 0000 0101
)가 왼쪽으로 시프트됩니다 4 배 (예 : 5 << 4
)는 80
(2 진수 0101 0000
)의 값을 산출합니다. 값을 왼쪽 1 시간으로 이동하는 것은 값에 2를 곱하는 것과 같습니다. 예를 들면 다음과 같습니다.
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;
}
그러나 왼쪽 시프트 연산은 부호 비트를 포함하여 모든 비트를 왼쪽으로 시프트 할 것입니다 (예 :
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;
가능한 출력 : a = 2147483647, b = -2
일부 컴파일러에서는 예상 된 결과를 얻을 수 있지만 부호 비트가 영향을 받도록 부호있는 숫자를 왼쪽으로 이동하면 결과는 정의되지 않습니다 . 시프트하려는 비트 수가 음수이거나 왼쪽의 유형이 보유 할 수있는 비트 수보다 큰 경우에는 정의되지 않습니다 . 예를 들면 다음과 같습니다.
int a = 1;
int b = a << -1; // undefined behavior
char c = a << 20; // undefined behavior
비트 현명한 할당 연산자 연산자 <<=
를 사용하여 특별히 지정하지 않는 한 비트 현 왼쪽 쉬프트는 원래 값의 값을 변경하지 않습니다.
int a = 5; // 0101b
a <<= 1; // a = a << 1;
>> - 오른쪽 교대
int a = 2; // 0010b
int b = a >> 1; // 0001b
std::cout << "a = " << a << ", b = " << b << std::endl;
산출
a = 2, b = 1
왜
오른쪽 비트 현명한 이동은 왼쪽 값 ( a
)의 비트를 오른쪽 ( 1
)에 지정된 숫자로 이동시킵니다. 오른쪽 시프트의 연산은 표준이지만 부호있는 음수 의 오른쪽 시프트 비트는 구현 정의 이므로 휴대 가능함을 보장 할 수 없습니다. 예를 들면 다음과 같습니다.
int a = -2;
int b = a >> 1; // the value of b will be depend on the compiler
또한 시프트 할 비트 수가 음수 인 경우 정의되지 않습니다 (예 :
int a = 1;
int b = a >> -1; // undefined behavior
비트 현명한 대입 연산자 >>=
를 사용하여 특별히 지정하지 않는 한 비트 현명한 오른쪽 시프트는 원래 값의 값을 변경하지 않습니다.
int a = 2; // 0010b
a >>= 1; // a = a >> 1;