비트 연산자와 매크로
비트 논리 연산자 (Bitwise Logical Operators) *복습
**Bitwise Logical Operator(비트 논리 연산자)**는 정수 값을 비트 단위로 논리 연산을 수행하는 연산자이다. C 언어에는 &
(AND), |
(OR), ^
(XOR), ~
(Complement)의 네 가지가 있다.
연산자 | 기호 | 의미 |
---|---|---|
AND | & | 두 피연산자의 각 비트가 모두 1일 때만 1을 반환한다. |
OR | ` | ` |
XOR | ^ | 두 피연산자의 각 비트가 서로 다를 때 1을 반환한다. |
Complement | ~ | 단일 피연산자의 모든 비트를 반전시킨다(1의 보수). |
예를 들어, 정수 3과 5에 대해 &
연산을 수행하면 다음과 같다.
-
3의 32비트 이진수:
00000000 00000000 00000000 00000011
-
5의 32비트 이진수:
00000000 00000000 00000000 00000101
-
3 & 5
의 결과:00000000 00000000 00000000 00000001
(정수 1)
이동 연산자 (Shift Operators) *복습
**Shift Operator(이동 연산자)**는 변수의 비트들을 지정된 횟수만큼 왼쪽 또는 오른쪽으로 이동시키는 연산자이다.
연산자 | 기호 | 의미 |
---|---|---|
왼쪽 이동 | << | 비트를 왼쪽으로 이동시킨다. |
오른쪽 이동 | >> | 비트를 오른쪽으로 이동시킨다. |
-
왼쪽 이동 (
<<
): 비트를 왼쪽으로 이동시키고, 왼쪽 경계를 벗어나는 비트는 버려진다. 오른쪽의 빈자리는 모두 0으로 채워진다.a << b
연산은a
에2^b
를 곱하는 효과와 같다. -
오른쪽 이동 (
>>
): 비트를 오른쪽으로 이동시키고, 오른쪽 경계를 벗어나는 비트는 버려진다. 왼쪽의 빈자리는 원래 숫자의 부호 비트(최상위 비트)로 채워진다 (산술 시프트). 피연산자가 양수일 때a >> b
연산은a
를2^b
로 나누는 효과와 같다.
비트 회전 (Rotate)
비트 **Rotate(회전)**는 이동 연산과 달리 한쪽 끝에서 밀려나는 비트를 다른 쪽 끝으로 다시 채워 넣는 연산이다.
-
rotateLeft(num, n)
:(num << n) | (num >> (16-n))
(16비트 기준) -
rotateRight(num, n)
:(num >> n) | (num << (16-n))
(16비트 기준)
비트 마스크 (Bit Mask) *복습
**Bit Mask(비트 마스크)**는 특정 비트들만 선택하거나 값을 변경하기 위해 사용하는 상수나 변수이다.
-
특정 비트 값 확인: 확인하려는 비트 위치만 1이고 나머지는 0인 마스크를 만들어
&
연산을 수행한다.예를 들어, 변수
a
의 n번째 비트를 확인하는 일반식은(a & (1 << (n-1)))
이다. -
특정 비트 값 변경:
-
비트를 1로 설정 (Set):
|
연산을 사용한다. -
비트를 0으로 설정 (Clear): 해당 비트만 1인 마스크를
~
로 반전시킨 후&
연산을 사용한다. -
비트 반전 (Toggle):
^
연산을 사용한다.
-
매크로와 전처리기
시스템 정의 매크로
C언어는 디버깅 등의 편의를 위해 시스템에서 미리 정의된 매크로를 제공한다.
매크로 | 기능 |
---|---|
__FILE__ | 현재 컴파일 중인 파일의 이름을 나타낸다. |
__TIME__ | 소스 파일이 컴파일된 시간을 시:분:초 형식으로 나타낸다. |
__DATE__ | 소스 파일이 컴파일된 날짜를 년/월/일 형식으로 나타낸다. |
__LINE__ | 해당 매크로가 위치한 소스 코드의 줄 번호를 나타낸다. |
조건부 컴파일
전처리기 지시자를 사용하여 특정 조건에 따라 코드의 일부를 컴파일에 포함시키거나 제외시킬 수 있다.
-
#if
,#elif
,#else
,#endif
: 상수 수식을 평가하여 조건에 따라 코드를 포함한다. -
#ifdef
:defined
의 약자로, 뒤따르는 기호상수(매크로)가 정의되어 있으면 코드를 포함한다. -
#ifndef
:if not defined
의 약자로, 뒤따르는 기호상수가 정의되어 있지 않으면 코드를 포함한다. -
defined
연산자:#if defined(DEBUG)
와 같이 사용하여#ifdef DEBUG
와 동일한 기능을 수행할 수 있다.
전처리기를 이용한 디버깅
전처리기는 디버깅용 코드를 효율적으로 관리하는 데 매우 유용하다.
-
컴파일러 옵션 활용: 소스 코드에
#define DEBUG
를 직접 작성하는 대신, 컴파일러 명령어 옵션(cl -DDEBUG ...
)으로 매크로를 정의할 수 있다. 이를 통해 소스 코드 수정 없이 디버그 모드를 켜고 끌 수 있다. -
디버깅 코드 분리:
#ifdef DEBUG
또는#if defined(DEBUG)
를 사용하여 디버깅용printf
나cout
문장들을 감싸면,DEBUG
매크로가 정의되지 않았을 때 해당 코드들이 최종 실행 파일에서 완전히 제거되어 프로그램의 성능에 영향을 주지 않는다. -
디버깅용 매크로 함수: 디버깅 코드를 매크로 함수로 만들어 코드를 더 깔끔하게 관리할 수 있다.
#if defined(DEBUG)
#define DebugCode(code_fragment) { code_fragment }
#else
#define DebugCode(code_fragment) // 아무것도 하지 않음
#endif
// 사용 예시
DebugCode(cout << "Selected = " << select << endl;);