[Rookiss C++] 연산

황교선·2023년 3월 15일
0

cpp

목록 보기
4/19

연산

식이 나타낸 일정한 규칙에 따라 계산함

연산자 종류

대입 연산자

=

  • 변수에 값을 대입할 때 사용하는 이항 연산자
  • 피연산자들의 결합 방향은 오른쪽에서 왼쪽
  • 산술 연산자와 비트 연산자 등을 결합하여 사용하는 복합 대입 연산자가 있음
int a = 1; // a라는 이름의 바구니를 만들고 안에 1을 넣는다(1을 대입한다)
int b = 2; // b라는 이름의 바구니를 만들고 안에 2를 넣는다(2를 대입한다)
a = b; // a에 b의 값을 넣어라(a = 2, b = 2인 상태)

산술 연산자

  • 사칙연산, 나머지연산을 다루는 기본적인 연산자
  • 모두 두 개의 피연산자를 가지는 이항 연산자
  • 피연산자들의 결합 방향은 왼쪽에서 오른쪽
산술 연산자설명
+왼쪽의 피연산자에 오른쪽 피연산자를 더함
-왼쪽의 피연산자에서 오른쪽 피연산자를 뺌
*왼쪽의 피연산자에서 오른쪽의 피연산자를 곱함
/왼쪽의 피연산자를 오른쪽의 피연산자로 나눔
%왼쪽의 피연산자를 오른쪽의 피연산자로 나눈 후, 그 나머지를 반환
int a = 1, b = 1;
a = b + 3; // b에 3을 더한 값을 a에 넣어라         [a = 4, b = 1]
a = b - 3; // b에 3을 뺀 값을 a에 넣어라          [a = -2, b = 1]
a = b * 3; // b에 3을 곱한 값을 a에 넣어라         [a = 3, b = 1]
a = b / 3; // b에 3을 나눈 값을 a에 넣어라         [a = 0, b = 1]
a = b % 3; // b에 3을 나눈 후 나머지 값을 a에 넣어라 [a = 1, b = 1]

a의 값만 계속 바뀌는 이유는, b의 값은 건들지 않으면서도 b와 3과의 연산으로만 이루어지고 이를 a에 대입하는 것이기 때문이다. 또한 나누기 연산에서 a의 값이 0.333… 이 아니고 0인 이유는 두 변수의 자료형이 정수형이기 때문이다. 정수형에서는 소수점을 처리할 수가 없기 때문에 버림하여 대입하면 0이기 때문이다.

증감 연산자

  • 1씩 증가 또는 감소 시킬 때 사용
  • 전위 연산과 후위 연산의 차이점에 주의할 것
증감 연산자설명
++x[전위] 피연산자의 값을 1 증가시킨 후, 해당 연산을 진행함
x++[후위] 먼저 해당 연산을 진행한 후, 피연산자의 값을 1 증가시킴
—x[전위] 피연산자의 값을 1 감소시킨 후, 해당 연산을 진행
x—[후위] 먼저 해당 연산을 진행한 후, 피연산자의 값을 1 감소시킴
int a = 10;
a = a + 1; // [a = 11]
a++; // [a = 12]
++a; // [a = 13]
a--; // [a = 12]
--a; // [a = 11]
int a = 3;
int b = 5;
int c;
c = ++a + b--; // 보통은 이렇게 사용하진 않겠지만 이해하기 위하여 설정

우선 a 앞에 전위 증가 연산자가 있기 때문에 a의 값을 1 더하여 4로 만든다. 그리고 a + b 연산을 수행하고 이를 c에 넣으면 c의 값은 9가 된다. 이후 b의 후위 감소 연산자를 계산하여 b = 4로 만든다.

최종 상태 : a = 4, b = 4, c = 9

비교 연산자

  • 피연산자 사이의 상대적인 크기를 판단할 때 사용
  • 어느 쪽이 더 큰지, 작은지, 같은지를 판단
  • C++에서 거짓(false)는 0이며, 0이 아닌 모든 것은 참(true)으로 인식함

언제 필요한가?

  • ex) 체력이 0이 되면 사망
  • ex) 체력이 30% 이하이면 궁극기를 발동
  • ex) 경험치가 100 이상이면 레벨업
비교 연산자설명
==왼쪽의 피연산자와 오른쪽의 피연산가 같으면 1을 반환
!=왼쪽의 피연산자와 오른쪽의 피연산자가 같지 않으면 1을 반환
>왼쪽의 피연산자가 오른쪽의 피연산자보다 크면 1을 반환
>=왼쪽의 피연산자가 오른쪽의 피연산자보다 크거나 같으면 1을 반환
<왼쪽의 피연산자가 오른쪽의 피연산자보다 작으면 1을 반환
<=왼쪽의 피연산자가 오른쪽의 피연산자보다 작거나 같으면 1을 반환
// a == b : a와 b의 값이 같은가?
bool isSame = a == b; // 같으면 1, 다르면 0

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

// a > b : a가 b보다 큰가?
bool isGreater = a > b; // 크면 1, 작으면 0

// a < b : a가 b보다 작은가?
bool isSmaller = a < b; // 작으면 1, 크면 0

비교 연산자를 수행하여 담기는 데이터는 0 또는 1이다. 이는 bool 변수에 담거나 조건문(뒤에 나오는개념)에서 검사하여 조건에 따른 문장을 나누어 실행하고 싶을 때 사용한다. 후자일 경우에는 변수에 담을 필요가 없어 변수명을 지어줄 필요는 없지만, 만약 전자처럼 변수에 담아서 꾸준히 사용하고 싶을 경우 bool 자료형으로 만들어 네이밍은 보통 is로 시작하여 작명한다.

논리 연산자

언제 필요한가?

  • 조건에 대한 논리적 사고가 필요할 때
  • ex) 로그인할 때 아이디도 같고 비밀번호도 같아야 한다
  • ex) 길드 마스터이거나 OR 운영자 계정이면 길드 해산 가능
논리 연산자설명
&&[AND] 논리식이 모두 참이면 1을 반환
![NOT] 논리식의 결과가 참이면 0을, 거짓이면 1을 반환

논리 연산 진리표

ABA && B [AND]A
11110
10010
01011
00001
bool isGuildMaster = false;
bool isAdmin = true;

if (isGuildMaster || isAdmin)
	cout << "Access Allowed" << endl;
else
	cout << "Access Denied" << endl;
bool hasPosion = true;
bool isMaxHP = true;

if (hasPosion && isMaxHP)
		cout << "Can't drink Posion" << endl;

논리 연산자에서 알아야하는 것은 앞의 조건으로만 전체 조건을 확인할 수 있으면 뒤의 조건을 확인하지 않아도 된다. 만약 and 연산을 하는데 앞의 조건이 거짓이라면 and 연산 진리표에서 볼 수 있듯이 하나가 거짓이면 무조건 거짓이기 때문에 바로 거짓이라는 값이 나온다. 또한 or 연산에서 하나라도 참이면 결과는 참이기 때문에 or 연산에서 앞의 조건이 참이면 뒤의 조건은 확인하지 않는다.

비트 연산자

  • 논리 연산자와 비슷하지만 비트 단위로 논리 연산을 할 때 사용
  • 비트 단위로 왼쪽이나 오른쪽으로 자료형의 비트 전체를 이동하거나, 1의 보수를 만들 때도 사용

언제 필요한가?

  • 잘 사용하지는 않음
  • 비트 단위의 조작이 필요할 때
  • 대표적으로 BitFlag
비트 연산자설명
&[bit AND] 대응되는 비트가 모두 1이면 1을 반환함
^[bit XOR] 대응되는 비트가 서로 다르면 1을 반환함
~[bit NOT] 비트를 1이면 0으로, 0이면 1로 반전시킴
<<[Left Shift] 지정한 수만큼 비트들을 전부 왼쪽으로 이동시킴
>>[RIght Shift] 부호를 유지하면서 지정한 수만큼 비트를 전부 오른쪽으로 이동시킴
#include <iostream>
using namespace std;

int main() {
    int a = 23985;
    int b = 12409;
    cout << "a : " << bitset<32>(a) << "\n";
    cout << "b : " << bitset<32>(b) << "\n";
    cout << "& : " << bitset<32>(a&b) << "\n";
    cout << "| : " << bitset<32>(a|b) << "\n";
    cout << "^ : " << bitset<32>(a^b) << "\n";
    cout << "~ : " << bitset<32>(~a) << "\n"; // ~는 단항 연산자
    cout << "<<: " << bitset<32>(a<<5) << "\n"; // b의 값이 너무 커서 현재 담겨있는 비트를 다 밀어서 지워버리기 때문에 작은 상수 5 사용
    cout << ">>: " << bitset<32>(a>>5) << "\n"; // b의 값이 너무 커서 현재 담겨있는 비트를 다 밀어서 지워버리기 때문에 작은 상수 5 사용
}
// 출력결과
// a : 00000000000000000101110110110001
// b : 00000000000000000011000001111001
// & : 00000000000000000001000000110001
// | : 00000000000000000111110111111001
// ^ : 00000000000000000110110111001000
// ~ : 11111111111111111010001001001110
// <<: 00000000000010111011011000100000
// >>: 00000000000000000000001011101101

복합 연산자

  • 대입 연산자에 사칙 연산자 혹은 비트 연산자를 결합하여 식을 짧게 만들기 위해 사용
#include <iostream>
using namespace std;

int main() {
    int a = 2;
    int b = 3;

    a += b;
    cout << "+= : " << a << ", " << b << endl;
    a -= b;
    cout << "-= : " << a << ", " << b << endl;
    a *= b;
    cout << "*= : " << a << ", " << b << endl;
    a /= b;
    cout << "/= : " << a << ", " << b << endl;
    a %= b;
    cout << "%= : " << a << ", " << b << endl;
    a &= b;
    cout << "&= : " << a << ", " << b << endl;
    a |= b;
    cout << "|= : " << a << ", " << b << endl;
    a ^= b;
    cout << "^= : " << a << ", " << b << endl;
    a <<= b;
    cout << "<<=: " << a << ", " << b << endl;
    a >>= b;
    cout << ">>=: " << a << ", " << b << endl;
}
// 출력결과
// += : 5, 3
// -= : 2, 3
// *= : 6, 3
// /= : 2, 3
// %= : 2, 3
// &= : 2, 3
// |= : 3, 3
// ^= : 0, 3
// <<=: 0, 3 // 이미 0인 상태에서 0으로만 된 비트를 좌 우로 옮겨봤자 0이기 때문
// >>=: 0, 3 // 이미 0인 상태에서 0으로만 된 비트를 좌 우로 옮겨봤자 0이기 때문

기타 연산자

  1. 삼항 연산자
    • 유일하게 피연산자를 세 개나 가지는 조건 연산자
    • 조건식 ? 반환값1 : 반환값2
    • 물음표 앞의 조건식에 따라 결괏값이 참이면 반환값1을 반환하고 결괏값이 거짓이면 반환값2를 반환
  2. 쉼표 연산자
    • 두 연산식을 하나의 연산식으로 나타내고자 할 때 사용
    • 둘 이상의 인수를 함수로 전달하고자 할 때 사용
  3. sizeof 연산자
    • 사용자의 컴퓨터 환경에 따라 타입에 할당되는 메모리의 크기가 달라질 수 있음
    • 피연산자의 크기를 바이트 단위로 반환
    • 타입(자료형)뿐만 아니라 변수나 상수도 올 수 있음
int a = 2;
int b = 5;
int c = (a > b) ? a : b; // a가 더 크면 a를 c에 대입하고, b가 더 크다면 b를 대입하라.
int d, e; // d와 e를 한 줄에 선언하는 방법(쉼표 연산자 사용)

int size = sizeof(int); // sizeof 연산자 사용 방법
size = sizeof(a);

C++ 연산자

  1. 범위 지정 연산자

    • 여러 범위에서 사용된 식별자를 식별하고 구분하는데 사용하는 연산자
    • 다시말해, 여러 영역에서 같은 이름의 변수가 있다면 이를 식별하도록 어디 영역의 이름인지 지정
  2. 멤버 포인터 연산자

    • 클래스의 멤버를 가르키는 포인터를 정의할 수 있음

    두 가지의 연산자

    1. 왼쪽의 피연산자가 클래스 타입의 객체인 경우 : .*
    2. 왼쪽의 피연산자가 클래스 타입의 객체를 가르키는 포인터인 경우 : →*
  3. typeid 연산자

    • 객체의 타입에 관한 정보를 확인할 수 있음
    • 런타임에 객체의 타입을 결정하는데 사용
    • 템플릿에서 템플릿의 매개변수의 타입을 결정할 때도 사용
//범위 지정 연산자 문법
::식별자
클래스이름::식별자
네임스페이스::식별자
열거체::식별자

//멤버 포인터 연산자 문법
클래스타입객체.*멤버이름
클래스타입객체의포인터->*멤버이름

//typeid
typeid(표현식)

연산의 우선순위

우선 순위 및 설명기호
결합성 없음::
왼쪽에서 오른쪽 연결성.[], ()(후위)++,
(후위)—xx_casttypeid
오른쪽에서 왼쪽 결합성sizeof++(전위),
—(전위)~, !-(단항 부정),
+(단항 긍정)&, *new,
delete() 캐스트
왼쪽에서 오른쪽 연결성.*→*
왼쪽에서 오른쪽 결합성*/%
왼쪽에서 오른쪽 연결성+-
왼쪽에서 오른쪽 연결성<<>>
왼쪽에서 오른쪽 연관성<><=>=
왼쪽에서 오른쪽 연결성==!=
왼쪽에서 오른쪽 연관성&
왼쪽에서 오른쪽 연관성^
왼쪽에서 오른쪽 연결성
왼쪽에서 오른쪽 연관성&&
왼쪽에서 오른쪽 결합성
오른쪽에서 왼쪽 결합성? :=*=, /=, %=+=, -=<<=, >>=&=,=, ^=
왼쪽에서 오른쪽 결합성,

자료형 변환

  • 범위가 더 큰 값을 범위가 작은 값의 변수로 옮길 때 오버플로우가 일어남
  • 정수 * 정수를 하는데 둘 다 큰 값이면 오버플로우
  • 정수 / 정수를 할 때 소수점 부분이 버려지는 것
profile
성장과 성공, 그 사이 어딘가

0개의 댓글