[C++] 시프트 연산자 - 논리 시프트, 산술 시프트

2025. 7. 14. 12:38·C++

1. 개념

시프트 연산 "<<" 혹은 ">>" 연산자로 비트를 이동시킬 때, 왼쪽 시프트 연산자인 "<<"는 항상 비트의 오른쪽에 생긴 빈 자리에 0을 채우지만, 오른쪽 시프트 연산자인 ">>"를 사용하게 되면 왼쪽에는 0 또는 1이 채워지게 된다. 보통 부호가 없으면 0이 채워지고 부호가 있으면 1이 채워지는데, 오른쪽 시프트 연산자를 사용하면 위와 같은 차이가 생기는 이유가 무엇일까?

 

결론적으로, 양수일경우와 부호가 없는(unsigned) 정수일 경우 논리 시프트가, 음수일 경우 산술 시프트가 사용되어 오른쪽 시프트 연산자를 사용할 때 차이가 발생한다.

해당 이유에 대해 파악하기 위해서 우선 세가지 개념( 논리 시프트, 산술 시프트, 보수법 )에 대해 추가로 학습해야한다.

논리 시프트

컴퓨팅에서 논리 시프트(logical shift)는 피연산자의 모든 비트를 이동하는 시프트 연산이다.

 

논리 시프트에서는 부호를 고려하지 않고 단순히 비트이동만 필요할 때 사용하는 형식인 것 같다. 해당 부분을 확인해보기 위해 양수값과 음수값을 논리 시프트 시켜서 값을 확인해 보았다.

#include <iostream>
#include <bitset>
using namespace std;

int main() {
	int pos = 8;
	int neg = -8;

	unsigned int unsignedPos = static_cast<unsigned int>(pos);
	unsigned int unsignedNeg = static_cast<unsigned int>(neg);

	unsigned int shiftedPos = unsignedPos >> 1;
	unsigned int shiftedNeg = unsignedNeg >> 1;

	cout << "--- 양수 8의 논리 시프트 결과 --- \n";
	cout << "원본 값 (10진수): " << pos << '\n';
	cout << "원본 값 (2진수): " << bitset<8>(unsignedPos) << '\n';
	cout << "논리 시프트 >> 1의 결과 (10진수): " << shiftedPos << '\n';
	cout << "논리 시프트 >> 1의 결과 (2진수): " << bitset<8>(shiftedPos) << '\n';
	cout << "--- 음수 -8의 논리 시프트 결과 --- \n";
	cout << "원본 값 (10진수): " << neg << '\n';
	cout << "원본 값 (2진수): " << bitset<32>(unsignedNeg) << '\n';
	cout << "논리 시프트 >> 1의 결과 (10진수): " << shiftedNeg << '\n';
	cout << "논리 시프트 >> 1의 결과 (2진수): " << bitset<32>(shiftedNeg) << '\n';
	return 0;
}

실행 결과

산술 시프트

논리 시프트와 동일하게 비트를 이동하는 연산이나, 산술 시프트는 부호비트(sign bit)가 보존되는 시프트 연산이다.

 

산술 시프트에서는 부호를 고려하여 비트이동을 한다고 했기 때문에, 해당 부분을 확인해보기 위해 양수값과 음수값을 산술 시프트 시켜서 값을 확인해 보았다.

#include <iostream>
#include <bitset>
using namespace std;

int main() {
	int pos = 8;
	int neg = -8;

	int shiftedPos = pos >> 1;
	int shiftedNeg = neg >> 1;

	cout << "--- 양수 8의 산술 시프트 결과 --- \n";
	cout << "원본 값 (10진수): " << pos << '\n';
	cout << "원본 값 (2진수): " << bitset<8>(pos) << '\n';
	cout << "산술 시프트 >> 1의 결과 (10진수): " << shiftedPos << '\n';
	cout << "산술 시프트 >> 1의 결과 (2진수): " << bitset<8>(shiftedPos) << '\n';
	cout << "--- 음수 -8의 산술 시프트 결과 --- \n";
	cout << "원본 값 (10진수): " << neg << '\n';
	cout << "원본 값 (2진수): " << bitset<8>(neg) << '\n';
	cout << "산술 시프트 >> 1의 결과 (10진수): " << shiftedNeg << '\n';
	cout << "산술 시프트 >> 1의 결과 (2진수): " << bitset<8>(shiftedNeg) << '\n';
	return 0;
}

실행 결과

보수법

음수를 표현하고 뺄셈을 덧셈으로 바꾸어 계산하기 위해 사용하는 개념

 

1의 보수

  • 각 자리의 비트를 모두 반전시킨다

2의 보수

  • 1의 보수에 1을 더한다

2. 결론

맨 왼쪽 첫번째 비트는 부호 비트이다.

 

음수값에 대해서 statuc_cast<unsigned int>를 통해 부호없는 정수형으로 형변환을 한 뒤, 오른쪽으로 1칸 시프트 연산을 했을 때논리 연산자로 실행했을 경우에는 왼쪽에서 0이 채워지고, 캐스팅 과정없이 음수값을 산술 시프트로 실행했을 때는 왼쪽에서 1이 채워진다.

즉, 오른쪽 시프트는 자료형의 부호 유무에 따라 논리 시프트와 산술 시프트로 다르게 동작한다.

 

컴파일러에서 가장 왼쪽 비트 값이 1이면 음수라고 판단하여 아래와 같은 과정으로 음수값을 도출해낸다.

  • 2진수의 음수 표현법

8 (0000 1000) → 1의 보수 (1111 0111) → 2의 보수(1111 1000) → -8 (1111 1000)

  • 음수값을 양수값으로 변환하기 위해서는 동일하게 1의 보수 → 2의 보수 과정을 거침

-8 (1111 1000) → 1의 보수 (0000 0111) → 2의 보수 (1111 1000) → 8 (1111 1000) 출력시 -8

'C++' 카테고리의 다른 글

[C++] 콘솔 텍스트에 색상을 적용시키는 2가지 방법  (0) 2025.06.25
[C++] System() 함수 - "cls" , "pause"  (0) 2025.06.13
[C++] 얕은 복사 vs 깊은 복사  (1) 2025.06.12
[C++] 스마트 포인터(Smart Pointer) 개념 정리  (0) 2025.06.12
[C++] 헤더파일 중복방지 #Pragma once vs #ifndef ~ endif  (0) 2025.06.10
'C++' 카테고리의 다른 글
  • [C++] 콘솔 텍스트에 색상을 적용시키는 2가지 방법
  • [C++] System() 함수 - "cls" , "pause"
  • [C++] 얕은 복사 vs 깊은 복사
  • [C++] 스마트 포인터(Smart Pointer) 개념 정리
_Bin_
_Bin_
  • _Bin_
    빈코드 (이전중)
    _Bin_
  • 전체
    오늘
    어제
  • 글쓰기 관리
    • 전체보기 (75)
      • C++ (8)
      • Unreal Engine (11)
      • Algorithm (6)
      • 컴퓨터지식(CS) (3)
      • 코딩테스트 (45)
      • 팀프로젝트 (1)
      • 기술면접 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    CS
    Red-Black Tree
    프로그래밍
    struct
    내일배움캠프
    프로그래머스
    코딩테스트
    SOLID원칙
    Algorithm
    class
    AVL Tree
  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.3
_Bin_
[C++] 시프트 연산자 - 논리 시프트, 산술 시프트
글쓰기상단으로

티스토리툴바