평생 공부하는 빠타박스 블로그 : Learning is Happiness
article thumbnail
SMALL

 - "본 내용은 Inflearn에 Rookies 강사님의 강의로 학습하고 있는 내용입니다."-


>>>> 이전 내용 : 산술연산자


 

이런 것들 수학을 하다보면 배웠을 것이다. 조금 다른 부분도 있지만 간단하다. 

아래 코드 내용 부분에 이러한 부분이 있다 라고만 판단하고 읽으면 될 것 같다

 

중요한 것은

1. 연산자를 어떻게 사용하는가?

2. 연산자의 우선순위

3. 논리 연산자가 이루어지는 방식(최적화?) 

 

분류 기호  설명 result
비교 연산자 a > b  a의 값이 b보다 큰가? a가 크다면 1 반환 b가 크다면 0 반환
a >= b a의 값이 b의 값보다 크거나 같은가? a가 크거나 같으면 1 아니면 0
a < b a의 값이 b 보다 작은가? a가 작으면 1 아니라면 0
a <= b a의 값이 b보다 작거나 같은가? a가 작거나 같으면 1 아니면 0
 a == b a의 값과 b의 값이 같은가? a와 b가 같다면 1 아니면 0 
a != b a의 값과 b의 값이 다른가? a의 값과 b의 값이 다르면 1 아니면 0 
논리 연산자 a  &&  b 앞에 있는 조건과 뒤에 조건이 모두 만족하는가? a의 조건도 b의 조건도 맞다면 1 아니면 0 
a || b 앞에 조건이든 뒤에 조건이든 하나라도 만족하는가? a나 b의 조건 어느하나라도 맞으면 1 둘다 아니면 0 
!a a는 아니다! (값을 뒤집어 준다) a의 값이 true(1)면 false(0) , false(0)이면 true(1) 

 

 

코드 내용 > 

더보기
/*비교& 논리 연산*/
#include <iostream>
using namespace std;

// 주제 : 데이터 연산
// 데이터를 가공하는 방법

int a = 1;
int b = 2;

bool isSame;
bool isDifferent;
bool isGreater;
bool isSmaller;


//논리
bool test;

int hp = 100;
bool isInvisible = true; // 무적여부

int main()
{
#pragma region 비교연산
	// 언제 필요한가?
	// ex ) 체력이 0이 되면 사망
	// ex ) 체력이 30% 이하이면 궁극기를 발동 (100* hp / maxHp) 와 같이
	// ex ) 경험치가 100 이상이면 레벨업

	// a == b : a와 b의 값이 같은가?
	// 같으면 1, 다르면 0

	isSame = (a == b); // a가 b 같다면 1 틀리면 0 이 들어간다.

	// a != b : a와 b의 값이 다른가?
	// 다르면 1, 다르면 0
	isDifferent = (a != b);

	// a > b  : a가 b보다 큰가?
	// a >= b : a가 b보다 크거나 같은가?
	// 1 아니면 0
	isGreater = (a > b);

	// a < b : a가 b 보다 작은가?
	// a <= b : a가 b보다 작거나 같은가?
	isSmaller = (a < b);

#pragma endregion

#pragma region 논리 연산
	// 언제 필요? 조건에 대한 논리적 사고가 필요할 때 (여러 조건에 대한 판단)
	// ex ) 로그인 할 때 아이디도 같고 AND 비밀번호도 같아야한다.
	// ex ) 길드 해산 권한에 대한 길드 마스터 또는 어드민 계정이면 길드 해산이 가능하다 또는 둘 중 하나의 조건에 맞을 때 OR 논리연산자를 사용할 수 있다.

	// ! not
	// 0이면 1, 그 외 0
	test = !isSame; // 뒤집어준다 사실상 isDifferent의 의미


	// &&  and
	// a && b -> 둘다 1일 경우 1 , 그외는 0 (즉 둘다 만족해야한다.)
	test = (hp <= 0 && isInvisible == false); // 체력이 없고 무적도 아닌 것 = 죽음


	// ||  or
	// a || b -> 둘 중 한개만 1(true)여도 true 1, 둘다 0이면 0
	test = (hp > 0 || isInvisible == true); // 체력이 남아있고 무적상태인 경우 = 생존
	// !(hp <= 0 && isInvisible == false); 이런식으로도 만들 수 있다.
#pragma endregion
}

 

비교연산

	isSame = (a == b); // a가 b 같다면 1 틀리면 0 이 들어간다.
00471856  mov         eax,dword ptr [a (047A000h)]  
0047185B  cmp         eax,dword ptr [b (047A004h)]  
00471861  jne         __$EncStackInitStart+33h (047186Fh)  
00471863  mov         dword ptr [ebp-0C4h],1  
0047186D  jmp         __$EncStackInitStart+3Dh (0471879h)  
0047186F  mov         dword ptr [ebp-0C4h],0  
00471879  mov         cl,byte ptr [ebp-0C4h]  
0047187F  mov         byte ptr [isSame (047A1B8h)],cl  
  • a를 eax 레지스터에 넣어주고
  • cmp : eax 와 b를 비교한다.
  • jne(jump not equal) : 047186F(주소) h (16진수 형태 주소) 0047186F→ 으로 점프 하게끔 되어있다. 만약에 둘이 다르다 하면 0047186F mov dword ptr [ebp-0C4h],0 이 부분으로 와서 실행할 것이다. ebp-0C4h (스택주소) 스택 어딘가 0으로 셋팅해서 isSame을 false로 만드는 것
  • 만약 jne를 통과 못했다면 둘이 같다는 얘기이니까. 00471863 mov dword ptr [ebp-0C4h],1 1값을 넣어주고 jmp 00471879 mov cl,byte ptr [ebp-0C4h] 점프해서 cl 레지스터에 넣어주는 것을 볼 수 있다.
  • 그러니까. 0 이든 1이든 cl레지스터에 해당 값을 넣어서 isSame에 만들어준 곳에 결과물 바구니에 다시 넣어준다는 것
  • 임시적으로 보관해서 최종적으로 넣어주는 것 (한 줄 이였던 게 이렇게 길게 작동한다)

 


	isDifferent = (a != b);
00471885  mov         eax,dword ptr [a (047A000h)]  
0047188A  cmp         eax,dword ptr [b (047A004h)]  
00471890  je          __$EncStackInitStart+62h (047189Eh)  
00471892  mov         dword ptr [ebp-0C4h],1  
0047189C  jmp         __$EncStackInitStart+6Ch (04718A8h)  
0047189E  mov         dword ptr [ebp-0C4h],0  
004718A8  mov         cl,byte ptr [ebp-0C4h]  
004718AE  mov         byte ptr [isDifferent (047A1B9h)],cl

 

 


	isGreater = (a > b);
004718B4  mov         eax,dword ptr [a (047A000h)]  
004718B9  cmp         eax,dword ptr [b (047A004h)]  
004718BF  jle         __$EncStackInitStart+91h (04718CDh)  
004718C1  mov         dword ptr [ebp-0C4h],1  
004718CB  jmp         __$EncStackInitStart+9Bh (04718D7h)  
004718CD  mov         dword ptr [ebp-0C4h],0  
004718D7  mov         cl,byte ptr [ebp-0C4h]  
004718DD  mov         byte ptr [isGreater (047A1BAh)],cl  

 

 

 


	isSmaller = (a < b);
004718E3  mov         eax,dword ptr [a (047A000h)]  
004718E8  cmp         eax,dword ptr [b (047A004h)]  
004718EE  jge         __$EncStackInitStart+0C0h (04718FCh)  
004718F0  mov         dword ptr [ebp-0C4h],1  
004718FA  jmp         __$EncStackInitStart+0CAh (0471906h)  
004718FC  mov         dword ptr [ebp-0C4h],0  
00471906  mov         cl,byte ptr [ebp-0C4h]  
0047190C  mov         byte ptr [isSmaller (047A1BBh)],cl

 

 

 

 

논리연산

	test = !isSame; // 뒤집어준다 사실상 isDifferent의 의미
00471912  movzx       eax,byte ptr [isSame (047A1B8h)]  
00471919  test        eax,eax  
0047191B  jne         __$EncStackInitStart+0EDh (0471929h)  
0047191D  mov         dword ptr [ebp-0C4h],1  
00471927  jmp         __$EncStackInitStart+0F7h (0471933h)  
00471929  mov         dword ptr [ebp-0C4h],0  
00471933  mov         cl,byte ptr [ebp-0C4h]  
00471939  mov         byte ptr [test (047A1BCh)],cl  
  • isSame 바구니안에 값을 eax에 넣어주고 test라는 작업을 한다.
  • test가 AND 연산이라고 생각하면 되는데 eax eax되어있는데jne (jump not equal)에 걸리면 해당 값이 0이 아니였다는 것
  • “자기 자신이랑 하는데 왜 하지? 싶긴 하다. “ 이게 왜냐하면 결과물에 따라 ZeroFlag 가 영향을 받기 때문에, 연이어서 cmp 하고 점프 했던 것과 마찬가지로 test와 jne를 연이어서 응용할 수 있다는 것을 알 수 있다. 즉 eax , eax 하는 현재 지금 test는 0인지 아닌지 판별하는 것이다.
  • 0이 아니였다면 00471929 mov dword ptr [ebp-0C4h],0 이곳 주소로 오게되어 점프해서 0을 집어넣고
  • 만약 0이였으면 0047191D mov dword ptr [ebp-0C4h],1 ebp-0C4h 부분에 1을 넣어줬을 것이다.
    • ebp-0C4h 는 스택프레임 어딘가 1 또는 0등이 들어간다(일종의 스택의 메모장 같은곳이다 임시저장소)
  • 최종적으로 cl 레지스터에 넣어주고 cl레지스터의 값을 test에 넣어주는 것을 볼 수 있다.

 

 


✅ ZeroFlag와 Sign Flag

Zero Flag 연산 결과가 0이면 참(1)

Sign Flag(부호 플래그)

연산 결과가 음수이면 참(1)

 


 

죽었다는 것을 판단

	test = (hp <= 0 && isInvisible == false); // 체력이 없고 무적도 아닌 것 = 죽음
0047193F  cmp         dword ptr [hp (047A008h)],0  
00471946  jg          __$EncStackInitStart+123h (047195Fh)  
00471948  movzx       eax,byte ptr [isInvisible (047A00Ch)]  
0047194F  test        eax,eax  
00471951  jne         __$EncStackInitStart+123h (047195Fh)  
00471953  mov         dword ptr [ebp-0C4h],1   // 최종 (만약 전부 만족)
0047195D  jmp         __$EncStackInitStart+12Dh (0471969h)  
0047195F  mov         dword ptr [ebp-0C4h],0  
00471969  mov         cl,byte ptr [ebp-0C4h]  
0047196F  mov         byte ptr [test (047A1BCh)],cl 
  • cmp에서 hp 값과 0과 비교 하고 hp 가 양수이면 jg
  • jg(jump greator) : 047195Fh 이곳 주소로 가서 0047195F mov dword ptr [ebp-0C4h],0 스택 어딘가 0이라는 값을 집어넣고 위 && AND 연산이 빠져나가서 바로 0이라는 결과를 알 수 있다.
    • 앞에 hp <= 0 의 결과가 만족하지 않았으면 앞에 보지도 않고 바로 빠져나온다.
  • jg 를 만족하지 않았다면 hp가 음수라는 것이 된다.
  • isInvisible에 byte(바구니)를 뽑아와서 eax레지스터에 저장하고
  • test eax, eax 값을 0인지 아닌지 판별한다.
  • 만약 isInvisible이 true면 && 문이 만족을 안하니까. 최종적으로 실패해서 바로 0047195F mov dword ptr [ebp-0C4h],0 로 와서 빠져나올 테고
  • 만약 다 통과 했다면 최종 결과물 00471953 mov dword ptr [ebp-0C4h],1 해당 값을 1로 셋팅해주고 cl로 다시 와서 test에 넣어주는 것을 볼 수 있다.

 

AND 연산의 특징을 볼 수 있듯이 먼저 왼쪽부터 체크를 하는 것을 볼 수 있다.

앞에 오느냐 뒤에 오느냐에 따라 성능 차이가 날 것으로 예상 된다.

 

 

	test = (hp > 0 || isInvisible == true); // 체력이 남아있고 무적상태인 경우 = 생존
00471975  cmp         dword ptr [hp (047A008h)],0  
0047197C  jg          __$EncStackInitStart+15Ah (0471996h)  
0047197E  movzx       eax,byte ptr [isInvisible (047A00Ch)]  
00471985  cmp         eax,1  
00471988  je          __$EncStackInitStart+15Ah (0471996h)  
0047198A  mov         dword ptr [ebp-0C4h],0  
00471994  jmp         __$EncStackInitStart+164h (04719A0h)  
00471996  mov         dword ptr [ebp-0C4h],1  
004719A0  mov         cl,byte ptr [ebp-0C4h]  
004719A6  mov         byte ptr [test (047A1BCh)],cl 
  • 여기는 hp > 0이 만족하면 그냥 보지도 않고 바로 넘어갈 것이다.
  • cmp 에서 hp에 값을 0인지 비교하는데 아니라면 jg 에 0471996 주소로 가서
  • 00471996 mov dword ptr [ebp-0C4h],1 바로 여기로 넘어와서 1로 넘겨주는 것을 볼 수 있다.비교연산

 

 

728x90
728x90
LIST
profile

평생 공부하는 빠타박스 블로그 : Learning is Happiness

@공부하는 PPATABOX

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!