[c++]연산자 (비교 연산자, 삼항 연산자, 비트 연산자)

TNT·2024년 2월 11일
0

c++ 기초

목록 보기
2/17

1. if

if문은 if, else, else if 로 나뉜다.

먼저 비교문을 생각하기 전에 비교 연산자에 대해서 알아야하는데
기본적으로

비교연산자

==  같음
!=  다름
>   보다 큼
<   보다 작음
>=  보다 크거나 같음
<=  보다 작거나 같음

종류는 이렇게 존재한다.

if문으로 어떻게 활용하냐면

int data = 0;

if (data == 0) {          // data 는 0이랑 값이 똑같나?
	data = 100;           // 참
}
else if (data != 100) {   // 아니라면 100이 아닌가?
	data = 10;            // 참
}
else {                    // 전부 아니라면 아래 실행
	data = 1;
}

비교 할때 주의 사항이 있는데 비교 할수있는 방식으로 서로 비교를 해줘야한다.

먼저 if 로 비교를 하고 바로 else 로 마무리 할수도있고 if만 적을수도있다.
사용 법은 다양 하니 적절하게 비교 문을 사용해보자.
만약 if에서 참이라서 들어갔을경우 아래 비교는 실행을 안한다.
즉 위에서 코드를 실행하면 data = 100이 된다.

2. switch

swhitch 문은 if문이랑 비슷하다고 볼수있는데 코드 보면서 설명하겠다.

int data = 0;

switch (data)    //data값이
{
case 0:          // 0이면 아래 실행
	data = 100;
	break;       // switch문 탈출
case 100:        // 100이면 아래 실행
	data = 10;
	break;       // switch문 탈출
default:         // 걸리는 비교가 없으면 아래 실행
	data = 1;
	break;       // switch문 탈출
}

data 값이 case랑 같은 경우 그 안에 있는 코드를 실행해 주는 구문 이다.
위에 보면 if문이랑 유사 하다.
보면 if문이랑 비슷하게 코드 설계했다.

break

근데 처음 보는 break; 가 생겼다.
break는 코드에 가장 가까운 바깥쪽 루프 또는 조건문의 실행을 종료 하는 명령어 이다.

여기서는 switch 문을 종료 시키고 나가게 하기 위해서 사용했다 만약에 없다고하면
비교후 0이라서 data = 100; 시키고 break로 switch 문 나가게 되는데 없다면 아래 코드도 실행 된다.
만약 아래도 없으면 default 까지 실행해버려서 data = 1이 되고 그다음 빠져 나온다.
잘 써주자 그러면 문법 실수가 아닌가 할수있는데 일부로 사용하는 경우도있다.

int data = 0;

switch (data)
{
case 0:
case 100:
case 200:
	data = 1000;
	break;
default:
	data = 1;
	break;
}

이런 경우는

int data = 0;

if (data == 0 || data == 100 || data 200) {
	data = 1000;
}else {
	data = 1;
}

이랑 같은 경우다 data가 0이거란 100이거나 200이면 안에 구문을 사용한다라고 사용도 가능하기 때문에 잘 써주자.

그럼 둘이 비슷한데 왜 나눠지냐고 하면 은근 조금씩 쓰는 경우가 다르기 때문에 둘다 알아두자.
가독성의 영역도 있고 실행하는 비교 조건에 따라서 좀 다른다.

삼항 연산자

삼한 연산자는 코드에 간결하게 하기 위에서 대입 할때 비교를 해버리는경우이다.
코드로 보면 이해가 오닌까 한번 보자.

int data = 0;
data == 0 ? data = 100 : data = 200;

위에 코드를 보면 먼저 if문 없이 비교를 한다
data == 0 ? 하고 물음표를 넣어서 삼항 연산자 인걸 표시하고
true 이면 data == 100 앞에문장일 실행
false 이면 data == 200 뒤에 문장을 실행 한다.

그러면 data 에 말고 다른 변수에 넣고 싶다면

int data = 0;

int a = data == 0 ? 100 : 200;
// 또는 
int a = data == 0 ? data : 200;

이런 느낌으로 다양하게 사용할수있다.

비트 연산자

난이도를 좀 올라가자 사용처도 조금 떨어지고 동작 방식도 까먹기 쉽다.
비트 연산자를 알려면 먼저 비트 쉬프트 에 대해서 알아야 하는데
저번 포스트에서 비트, 바이트 관련 알려주긴했지만 다시 정리 하겠다.

비트 시프트

비트 시프트는 비트를 왼쪽 << 또는 오른쪽 >> 으로 밀수 있다.

위 사진 처럼 코드를 작성 해서 보자.

	unsigned char c = 1;
	c = c << 2; // 4

	c = 8;
	c = c >> 2; // 2;

이게 공식으로 보면 비트 자리를 바꿔주는경우 이다. 새로 들어온 비트는 0 이 들어온다.


코드로 한번 확인해보자.

	unsigned char c = 100;
	c = c << 2; // 144

근데 c = c << 2; 는 조금 그러니 이걸 대입 연산자 써서 축약 시켜보자.

	unsigned char c = 100;
	c <<= 2; // 144

<<= 또는 >>= 으로 축약 시킬수있다 보기에도 더 좋다.
결국 이렇게 비트 1을 미는 행동이 왼쪽으로 밀면 2, 4, 8, 16, 32로 2의 거듭 제곱으로 으로 사용할수있다.
반대로 >> 밀면 2n으로 나눈 몫 즉

<< 는  2^n == 2의 거듭 제곱, 배수
>> 는  2^n == 2^n 나눈 몫

으로 볼수있다.

비트연산을 쉽게 설명하려면 나중에 쓸건데 전처리기를 먼저 사용하겠다.

#define

전처리기(preprocessor)는 프로그램을 컴파일할 때 컴파일 직전에 실행되는 별도의 프로그램이다.
전처리기가 실행되면 각 코드 파일에서 지시자(directives)를 찾는다.
지시자(directives)는 #으로 시작해서 줄 바꿈으로 끝나는 코드다.
전처리기는 컴파일러가 실행되기 직전에 단순히 텍스트를 조작하는 치환 역할을 하기도 하고, 디버깅에도 도움을 주며 헤더 파일의 중복 포함도 방지해주는 기능을 가진다.

이 사전 설명인데 좀 풀어서 설명하자면

컴파일러가 실행할때 전처리기 가 있으면 그 코드를 먼저 치환해서 대신 채운다.

#define HUNGRY 1

int main() {
	int iStatus = HUNGRY;  // int iStatus = 1;
	return 0;
}

비트 연산

비트 곱(&), 합(|), xor(^), 역(~)
으로 사용한다.
먼저 곱부터 보자.

비트 곱은 연산 하는경우 비트 단위로 하나 씩 같은 자리를 비교해서 처리한다.
비트 단위 기준으로 비교해서 둘중 하나 라도 0이있으면 0 둘다 1이면 1이다.

비트 합은 연산 하는경우 비트 단위로 하나 씩 같은 자리를 비교해서 처리한다.
비트 단위 기준으로 비교해서 둘중 하나 라도 1이있으면 0 둘다 0이면 0이다.

xor은 비트 끼리 비교후 같은 자리에 숫자가 같으면 0 다르면 1이다.

비트 역은 비트를 그래도 0 1 숫자를 반전 시킨다 0100 1000 을 1011 0111으로 표현한다.

뭔가 논리 연산이랑 비슷하다고 볼수있는데 비트 단위에서 하는 행위이다.
이걸 어디서 사용하냐 할수도있는데 예시를 게임을 들어 보겠다.

이런 코드가 있을경우 컴파일러가 #define 을 보고 HUNGRY 라는 구문을 보면 그걸 1으로 교체 해버리고 그다음에
코드를 실행한다.
그러면 이런 디파인 구문을 사용을 하냐면
보통 게임 캐릭터가 버프나 디버프 를 넣어줄때 Status를 해줘야하는데 프로그래머가 숫자로 기억하기도 힘들고
게임이 커지면 그 양이 엄청 나다 또는 2번을 스턴으로 지정했는데 나중에 수면으로 바꾸자고 하는경우 코드를 다 찾아서 넣어줘야한다.

그런걸 define 으로 걸어뒀기 때문에 숫자를 볼 필요가 없다
또는 코드에서 전부 수정해야할때도 define 에서 하나만 바꾸면 전체 적용이 가능하기 때문에 코드 가독성 유지보수 편의성이 높아진다.

비트 합 |

비트 합은 연산 하는경우 비트 단위로 하나 씩 같은 자리를 비교해서 처리한다.
비트 단위 기준으로 비교해서 둘중 하나 라도 1이있으면 0 둘다 0이면 0이다.

먼저 위에 보면 내 상태를 int형으로 표시 했다.
int형은 32 비트 이다.
그려면 이 상태를 조합해서 사용이 할수도있다. 그러면 이러한 상태가 한개만 아니고 여러개도 사용이 가능하기때문에
보면 int형은 한 플레이어에 32가지 상태를 표시 가능하다.

비트 1번칸은 0이면 안배고픈거 1이면 배고픈거로 사용한다고 하면
플레이어가 동시에 사용가능한 상태는 32가지 이다.


느낌이 왔다면 이걸 보면 바로 눈치 챌수 있을것이다.
한 비트 자리가
디버프가 된다. 그러면 이걸 나는 플레이어에 추가 하고싶어 일경우 대입 = 을 해도 좋은데 만약 2개이상 디버프면?

그러면 합쳐서 넣어줘야한다.

#define HUNGRY  1 //배고픔
#define THIRSTY 2 //목마름
#define TIRED   4 //피곤함

int main() {
	unsigned int iStateus = 0; // 평범 
    iStateus |= HUNGRY;        // 배고픔 추가
	iStateus |= TIRED;       // 피곤 추가
}

그러면 결과는 어케 될까

피곤함이랑 배고픔 둘다 체크할수있다. 한변수에서 말이다.
비트 합은 둘중 하나라도 1이면 1을 출력 하기 때문에 사용이 가능하다.

비트 곱 &

비트 곱은 연산 하는경우 비트 단위로 하나 씩 같은 자리를 비교해서 처리한다.
비트 단위 기준으로 비교해서 둘중 하나 라도 0이있으면 0 둘다 1이면 1이다.

그러면 이제 비교를 할수도있는지 확인을 해야하는데 이럴땐 어느방식으로 할수있을까?
그러경우 비트 곱으로 확인 할수있다.
둘다 비교 값 둘다 1이여야지 1을 반환하는데 이걸로 확인할수있다.

비트 곱은 비교 값이 둘다 같아야 1이기 때문에 원하는 상태만 체크 할수가 있다.
코드로 보자면

#define HUNGRY  1 //배고픔
#define THIRSTY 2 //목마름
#define TIRED   4 //피곤함

int main() {
	unsigned int iStateus = 0; // 평범 
    iStateus |= HUNGRY;        // 배고픔 추가
	iStateus |= TIRED;       // 피곤 추가

	if (iStateus & TIRED) {
		// 피곤함 처리
	}
}

if 문 보면 합으로 해서 결과가 0 이면 false 이고 결국 if 문실행이 안된다.
이렇게 비트 곱으로 비교를 할수있다.

그리면 이제 디버프가 끝났으면 상태를 빼야한다. 즉 비트를 하나만 제거 하고싶다면?

비트 xor ^

xor은 비트 끼리 비교후 같은 자리에 숫자가 같으면 0 다르면 1이다.

비트를 xor은 비트끼리 비교해서 같은 자리에 숫자가 같은경우만 0 틀리면 1이다.
위에 합 곱 처럼 똑같이 생각해보면 바로 알수있다.

숫자가 같으면 0 다르면 1이닌까 피곤함이 끝났으면 비트 xor을 해주면 풀린다.

그러면 비교를 먼저 하고 넣으면 된다.

#define HUNGRY  1 //배고픔
#define THIRSTY 2 //목마름
#define TIRED   4 //피곤함

int main() {
	unsigned int iStateus = 0; // 평범 
    iStateus |= HUNGRY;        // 배고픔 추가
	iStateus |= TIRED;       // 피곤 추가

	if (iStateus & TIRED) {
        iStateus ^= TIRED; // 피곤 제거
	}
}

근데 궁금한게 만약 피곤함이 없으면 넣어버리는 경우가 생긴다.
왜냐면 비교 할때 다르면 넣어버릴수도있어서 그렇다.
끝 이라고도 생각할수있는데 좀만 더 고민 해보면 사실 비교 안하고도 처리 할수있다.

이걸 사용한다면 코드 가독성도 높아지고 버그도 방지 할수도있다.

비트 역 ~

비트 역은 비트를 그래도 0 1 숫자를 반전 시킨다 0100 1000 을 1011 0111으로 표현한다.

코드를 먼저 보여주고 설명하겠다

#define HUNGRY  1 //배고픔
#define THIRSTY 2 //목마름
#define TIRED   4 //피곤함

int main() {
	unsigned int iStateus = 0; // 평범 
    iStateus |= HUNGRY;        // 배고픔 추가
	iStateus |= TIRED;       // 피곤 추가

	iStatus &= ~TIRED;       // 피곤 비트를 역으로 반전 시킨후 그걸 지금 스테이터스에 비트 곱해준다.
}

이렇게 하면 무슨일이 생기냐 하면

비트 곱 이 둘다 1이여야지 값을 1이 나오기 때문에 빼고 싶은 상태에 ~ 역으로 반전 시킨후 그값을 비트 곱으로 연산해주면
처리가 깔끔하게 된다 만약에 디버프가 없더라도 한쪽이 0이기때문에 디버프가 들어갈 일없다 방지도 가능하고 제거도 가능하고
if 둘 필요도 없기 때문에 편리하다.

비트 16진수

int비트 처리 하고있는데 1 2 4 8 16 ... 2의 n승으로 올라가는중이다.
근데 보통 코드를 보다보면 숫자 앞에 0x 넣는경우도 있는데 16진수로 처리를 많이 한다.
예시로 한번 보자.

#define HUNGRY  1 //배고픔
#define THIRSTY 2 //목마름
#define TIRED   4 //피곤함
#define FIRE    8

#define COLD    16
#define POISON  32
#define DEBUFF1 64
#define DEBUFF2 128

#define DEBUFF3  512
#define DEBUFF4  1024
#define DEBUFF5  2048
#define DEBUFF6  4096

// 또는
#define HUNGRY  0x1 //배고픔
#define THIRSTY 0x2 //목마름
#define TIRED   0x4 //피곤함
#define FIRE    0x8

#define COLD    0x10
#define POISON  0x20
#define DEBUFF1  0x40
#define DEBUFF2  0x80

#define DEBUFF3  0x100
#define DEBUFF4  0x200
#define DEBUFF5  0x400
#define DEBUFF6  0x800

뭐가 더 보기 깔끔해보이냐 하면 아래 가 더 숫자에 규칙성이 있고 반복이 있기때문에 확인하기가 더 좋다.

이런 비트가 상태 뿐만 아니라 여러곳에서도 많이 쓰긴다 ui 관련으로 첫 페이지 보상 구매 같은 창 뜨는것도 한번도 안뜬건지 체크해서 넣고 한번도 안본거면 창 보여주고 체크 넣고 하기도하고
또는 윈도우 창 우측 상단에 있는 저런 버튼도 다 윈도우 스타일 이라고해서 만들어둔 상태이다.

이곳 저곳에서 많이 사용하기 때문에 잘 알아두자.

profile
개발

0개의 댓글