Bitwise and shift operators
Peponi │ 11/18/2024 │ 7m
Bitwise and shift operators
Peponi
1. Introduction
Bitwise 및 shift 연산자는 피연산자에 대해 비트 연산을 수행하게 한다. 정수 형식 또는 문자형 (char)에 대해 비트 연산 수행이 가능하다.
정수 형식은 int
, uint
, long
, ulong
형식으로 정의된다. 피연산자가 다른 정수 형식인 (int
보다 작은 데이터형) 경우 연산 결과는 int
형식으로 변환된다. 피연산자의 형식이 다른 경우 값을 포함할 수 있는 가장 가까운 형식으로 변환된다.
복합 할당 식의 경우 결과 형식은 왼쪽 피연산자의 형식이다.
2. 비트 연산자
2.1. Complement
~
연산자는 피연산자의 각 비트를 뒤집어 비트 보수를 반환한다.
int A = 0b_1010_1011;
int B = ~A;
Console.WriteLine(Convert.ToString(A, 2).PadLeft(sizeof(int) * 8, '0'));
Console.WriteLine(Convert.ToString(B, 2));
/* output:
00000000000000000000000010101011
11111111111111111111111101010100
*/
2.2. AND
&
연산자는 피연산자의 각 비트에 대해 AND 연산을 수행한다.
int A = 0b_1010_1011;
int B = 0b_1101_1101;
int C = A & B;
Console.WriteLine(Convert.ToString(C, 2));
/* output:
10001001
*/
2.3. OR
|
연산자는 피연산자의 각 비트에 대해 OR 연산을 수행한다.
int A = 0b_1010_1011;
int B = 0b_1101_1101;
int C = A | B;
Console.WriteLine(Convert.ToString(C, 2));
/* output:
11111111
*/
2.4. XOR
^
연산자는 피연산자의 각 비트에 대해 XOR 연산을 수행한다.
int A = 0b_1010_1011;
int B = 0b_1101_1101;
int C = A ^ B; // 0b_0111_0110
Console.WriteLine(Convert.ToString(C, 2));
/* output:
1110110
*/
3. 시프트 연산자
3.1. Left shift
<<
연산자는 왼쪽 피연산자를 오른쪽 피연산자로 지정된 시프트 수만큼 왼쪽으로 이동시킨다. 결과 형식의 범위를 벗어나는 상위 비트는 삭제되고, 하위 비트는 자동으로 0
으로 설정된다.
byte A = 0b_0001;
int B = A << 8;
Console.WriteLine(Convert.ToString(A, 2));
Console.WriteLine(Convert.ToString(B, 2));
uint C = 0b_1001_0110_1100_0000_1110_1111_0010_0101;
uint D = C << 8; // 0b_1100_0000_1110_1111_0010_0101_0000_0000
Console.WriteLine(Convert.ToString(C, 2));
Console.WriteLine(Convert.ToString(D, 2));
/* output:
1
100000000
10010110110000001110111100100101
11000000111011110010010100000000
*/
3.2. Right shift
>>
연산자는 왼쪽 피연산자를 오른쪽 피연산자로 지정된 시프트 수만큼 오른쪽으로 이동시킨다.
byte A = 0b_1010_1101;
int B = A >> 3; // 0b_0001_0101
Console.WriteLine(Convert.ToString(B, 2).PadLeft(8, '0'));
/* output:
00010101
*/
결과 형식의 범위를 벗어나는 하위 비트는 삭제되고, 상위 비트는 다음과 같이 결정된다.
-
Signed type : 왼쪽 피연산자의 최상위 비트 값이 비어있는 상위 비트를 채운다.
(왼쪽 피연산자가 음수가 아닌 경우0
, 음수인 경우1
로 설정된다.)int A = 16; int B = A >> 3; Console.WriteLine(Convert.ToString(A, 2).PadLeft(sizeof(int) * 8, '0')); Console.WriteLine(Convert.ToString(B, 2).PadLeft(sizeof(int) * 8, '0')); int C = -16; int D = C >> 3; Console.WriteLine(Convert.ToString(C, 2)); Console.WriteLine(Convert.ToString(D, 2)); /* output: 00000000000000000000000000010000 00000000000000000000000000000010 11111111111111111111111111110000 11111111111111111111111111111110 */
-
Unsigned type : 오른쪽 시프트는 논리적 시프트를 수행하며 비어있는 상위 비트는
0
으로 채워진다.uint A = 0b_1000_0000_0000_0000_0000_0000_0000_0000; uint B = A >> 3; Console.WriteLine(Convert.ToString(A, 2)); Console.WriteLine(Convert.ToString(B, 2).PadLeft(sizeof(int) * 8, '0')); /* output: 10000000000000000000000000000000 00010000000000000000000000000000 */
3.2. Unsigned right shift
>>>
연산자는 왼쪽 피연산자를 오른쪽 피연산자로 지정된 시프트 수만큼 오른쪽으로 이동시킨다. >>>
연산자는 항상 논리적 시프트를 수행한다.
int A = 16;
int B = A >>> 3;
Console.WriteLine(Convert.ToString(A, 2).PadLeft(sizeof(int) * 8, '0'));
Console.WriteLine(Convert.ToString(B, 2).PadLeft(sizeof(int) * 8, '0'));
int C = -16;
int D = C >>> 3;
Console.WriteLine(Convert.ToString(C, 2).PadLeft(sizeof(int) * 8, '0'));
Console.WriteLine(Convert.ToString(D, 2).PadLeft(sizeof(int) * 8, '0'));
/* output:
00000000000000000000000000010000
00000000000000000000000000000010
11111111111111111111111111110000
00011111111111111111111111111110
*/
IMPORTANT
>>>
연산자는 C# 11부터 사용 가능하다.
3.3. 시프트 수
시프트 연산자의 오른쪽에 지정하는 시프트 수는 왼쪽 피연산자의 형식에 따라 달라진다.
-
왼쪽 피연산자의 형식이
int
또는uint
: 오른쪽 피연산자의하위 5bit
으로 정의된다.
오른쪽 피연산자 & 0b_0001_1111
int A = 0b_0001; int shift = 0b_1010_0011; int shifted = A << shift; Console.WriteLine(Convert.ToString(shifted, 2)); /* output: 1000 */
-
왼쪽 피연산자의 형식이
long
또는ulong
: 오른쪽 피연산자의하위 6bit
으로 정의된다.
오른쪽 피연산자 & 0b_0011_1111
long A = 0b_0001; int shift = 0b_1010_0000; int shift2 = 0b_1010_0011; long shifted = A << shift; long shifted2 = A << shift2; Console.WriteLine(Convert.ToString(shifted, 2)); Console.WriteLine(Convert.ToString(shifted2, 2)); /* output: 100000000000000000000000000000000 100000000000000000000000000000000000 */
4. 열거형 논리 연산자
열거형 형식에 대해 ~
, &
, |
, ^
연산자가 지원되며, 지정 값에 대해 비트 논리 연산이 수행된다. 일반적으로 [Flags]
특성으로 정의된 열거형 형식에 사용한다.
[Flags]
enum StatusCode
{
None = 0b_0, // 0
Idle = 0b_1, // 1
Run = 0b_10, // 2
Warning = 0b_100, // 4
Error = 0b_1000 // 8
}
StatusCode code = StatusCode.Idle | StatusCode.Warning | StatusCode.Error; // 13
Console.WriteLine(code); // Idle, Warning, Error
자세한 내용은 Enum type - 4. enum 비트 플래그를 참조한다.