[C++] 연산자(Operators), 전처리기[#define], 연산자 우선순위

2024. 2. 29. 10:07Programming Language/C++

아래 링크 클릭 시 해당 본문으로 이동

연산자(Operators)

전처리기 (#define)

비트 연산자 활용 예시

#define 상태 값

연산자 우선순위(Operator Precedence)


연산자(Operators)

연산 명령을 수행하는 기호

• 연산자 종류 : 대입 · 산술 · 복합 대입 · 증감 · 비교 · 논리 · 비트 연산자

피연산자 : 연산을 당하는 것, 연산하는 대상
이항 연산자 : 피연산자가 2개인 연산자 (산술/비교/대입/논리/비트 연산자 등)

1. 대입 연산자(Assignment Operators)

• 변수에 값을 대입할 때 사용하는 이항 연산자

오른쪽을 왼쪽에 대입한다.

※ 비교연산자 "=="와 헷갈리지 말기

대입 연산자 설명
= 오른쪽 피연산자를 왼쪽 피연산자에 대입

대입 연산자 사용 유무에 따른 차이점

int data = 20;  // 20

// 1. 대입 연산자 없이 연산
data + 20;  // 20
// 연산한 결과인 40을 다시 변수에 대입하지 않았기 때문에 data에는 20이 저장된다.

// 2. 대입 연산자 이용하여 연산
data = data + 20;  // 40
// 오른쪽에서 연산한 값을 40이 왼쪽에 있는 data에 대입했기 때문에 40이 저장된다.
연산자 우선순위에서 산술 연산자가 대입 연산자보다 높기 때문에 산술 연산자를 대입 연산자보다 먼저 연산한다.

 

▷ 예시

#include <iostream>

using std::cout;

int main()
{
	int i = 0;
	int i2 = 5;
	int i3 = 10;
	
    // i3를 i2에 넣은 뒤, i = i2;가 돼서 i2를 i에 넣는다.
    	// i2 = i3  →  i = i2
	i = i2 = i3;
    
    cout << i;
}

▽ 출력 결과

10

2. 산술 연산자(Arithmetic Operators)

• 사칙연산을 다루는 이항 연산자

산술 연산자 설명
+ 왼쪽 피연산자 + 오른쪽 피연산자
- 왼쪽 피연산자 - 오른쪽 피연산자
* 왼쪽 피연산자 × 오른쪽 피연산자
/ 왼쪽 피연산자 ÷ 오른쪽 피연산자
%
(모듈러스, 나머지 연산자)
왼쪽 피연산자 ÷ 오른쪽 피연산자

그 나머지를 반환

`%` (나머지 연산자)

• 피연산자가 모두 정수일 때만 사용할 수 있으며, 피연산자 중 하나라도 실수일 때는 사용할 수 없다.

실수끼리 나누면 결과도 실수이기 때문에 나머지가 존재하지 않는다. (ex. 10.5 ÷ 2.5 = 4.2)

만약 나머지가 있다고 해도 소수점 몇 번째 자리까지를 나머지로 볼 건지 그 기준이 애매하다.

`/` vs. `%`

int data = 0;
data = 10 / 3;  // 3
data = 10 % 3;  // 1
data = 10. % 3.;  // 오류
data = 10. / 3.;  // 3

data = 10. % 3.;에 오류가 뜸.

실수끼리 나누면 나머지가 존재하지 않기 때문에 오류가 발생한다.

 

data = 10. / 3.;

실수끼리의 연산임에도 결과는 정수인 이유는 연산의 결과를 받아갈 변수 `data` 정수형(int)이기 때문이다.

경고

이 경우 오류는 아니지만 경고가 발생하는데, 정수로 바꾸기 위해 연산 전체를 int로 묶어주면 경고가 사라진다.

data = (int)(10. / 3.);

경고가 사라짐.


3. 복합 대입 연산자(Compound Assignment Operators)

• 산술 연산자와 대입 연산자가 결합한 형태의 이항 연산자

• 연산할 때 코드를 좀 더 간단하게 작성할 수 있다.

복합 대입 연산자 설명
+= 왼쪽 피연산자 + 오른쪽 피연산자
↓ 
결과값을 왼쪽 피연산자에 대입
-= 왼쪽 피연산자 - 오른쪽 피연산자
↓ 
결과값을 왼쪽 피연산자에 대입
*= 왼쪽 피연산자 × 오른쪽 피연산자
↓ 
결과값을 왼쪽 피연산자에 대입
/= 왼쪽 피연산자 ÷ 오른쪽 피연산자
↓ 
결과값을 왼쪽 피연산자에 대입
%= 왼쪽 피연산자 ÷ 오른쪽 피연산자

나머지를 왼쪽 피연산자에 대입

'대입 연산자 + 산술 연산자' vs. '복합 대입 연산자'

// 1번과 2번 코드는 표현 방법만 다를 뿐, 같은 코드이다.
// 1. 대입 연산자, 산술 연산자
int data = data + 20;
// 하나의 코드 안에서 변수 data가 반복된다.

// 2. 복합 대입 연산자
data += 20;
// data에 20을 더한 결과를 다시 본인(data)한테 넣어준다.

4. 증감 연산자(Increment&Decrement Operators)

• 피연산자가 1개인 단항 연산자

한 단계 증감(증가 또는 감소)한다.

정수 실수에서 한 단계 증감은 1씩 증감하는 것을 의미한다.

포인터로 주소를 증감할 때처럼 한 단계라는 개념이 다른 경우가 있기 때문에 '1씩 증감한다.' 보다는 '한 단계 증감한다.'는 표현을 사용하는 게 더 좋다.

증감 연산자 설명
++x
(x는 변수)
① 피연산자 값 한 단계 증가
② 해당 연산 진행
x++ ① 해당 연산 진행
② 피 연산자 값 한 단계 증가
--x ① 피연산자 값 한 단계 감소
② 해당 연산 진행
x-- ① 해당 연산 진행
② 피 연산자 값 한 단계 감소

※ 특별히 구분 지을 상황이 아니면 증감 연산자는 전위 연산자를 사용하는 것이 좋다.

후위 연산자를 쓰다 보면 효율이 안 좋은 함수를 호출할 수 있기 때문이다.

1) 전위 연산자 (전치 연산자)

• `++` 또는 `--`가 피연산자 에 있다.

 증감 → 대입

#include <iostream>

using std::cout;
using std::endl;

int main()
{
	int c = 0;
    int data = 0;
    c = 10;
    data = ++c;
	cout << "c = " << c << ", " << "data = " << data << endl;  // c = 11, data = 11
    // ++c가 먼저 연산되고 data에 대입했기 때문에 data에는 11이 저장된다.

	return 0;
]

▽ 출력 결과

c = 11, data = 11

 

2) 후위 연산자 (후치 연산자)

• `++` 또는 `--`가 피연산자 에 있다.

 대입 → 증감

#include <iostream>

using std::cout;
using std::endl;

int main()
{
	int c = 0;
    int data = 0;
    c = 10;
    data = c++;
	cout << "c = " << c << ", " << "data = " << data << endl;  // c = 11, data = 10
    // c의 값을 먼저 data에 대입했기 때문에 data에는 10이 저장된다.

	return 0;
]

▽ 출력 결과

c = 11, data = 10

우선순위는 후위 연산자가 대입 연산자보다 더 높은데, `data`에 11이 아닌 10이 저장되어 있다.

후위 연산자에서는 연산 후 증가한 값을 반환한 것이 아니라 증가하기 전의 값을 반환했기 때문에 후위 연산자의 우선순위가 뒤로 밀린 것처럼 보인 것이지 진짜 대입 연산자보다 우선순위가 뒤로 밀린 게 아니다.

연산자 우선순위는 해당 본문 아래 페이지 참고
연산자 우선순위

전위 · 후위 연산자가 각각 단독으로 쓰일 때 vs. 다른 연산자와 같이 쓰일 때

① 단독으로 쓰일 때 (다른 연산자와 같이 쓰이지 않고 혼자만 쓰인 경우)
두 경우의 연산 결괏값은 같다.

// 1) 전위 연산자
int c1 = 5;
++c1;  // 6
// 2) 후위 연산자
int c2 = 5;
c2++;  // 6

② 다른 연산자와 같이 쓰일 때
두 경우의 연산 결괏값은 다르지만 연산이 완료된 후에 증감 연산자가 붙은 변수의 값은 같다.

// 1) 전위 연산자
int c1 = 3;
int c2 = 0;
c2 = ++c1 * 5;  // 변수 c1값 : 4, 변수 c2값 : 4 × 5 = 20
// 2) 후위 연산자
int c1 = 3;
int c2 = 0;
c2 = c1++ * 5;  // 변수 c2값 : 3 × 5 = 15, 변수 c1값 : 4

전위 연산자 : c1 = 4, c2 = 20

◦ 후위 연산자 : c1 = 4, c2 = 15

연산 결괏값인 `c2`값은 다르지만 연산이 끝난 후 `c1`의 값은 같다는 것을 알 수 있다.


5. 비교 연산자(Comparison Operators)

• 왼쪽 피연산자와 오른쪽 피연산자 비교하는 이항 연산자

• 비교한 결과가 false이면 `0`, true이면 `1`을 반환한다.

비교 연산자 설명
==
 대입 연산자 "="와 헷갈리지 말기
왼쪽 피연산자 =(대입 X, 같다는 의미) 오른쪽 피연산자

1 반환
!= 왼쪽 피연산자 ≠ 오른쪽 피연산자

1 반환
> 왼쪽 피연산자 > 오른쪽 피연산자

1 반환
>= 왼쪽 피연산자 >= 오른쪽 피연산자

1 반환
< 왼쪽 피연산자 < 오른쪽 피연산자

1 반환
<= 왼쪽 피연산자 <= 오른쪽 피연산자

1 반환

 

▷ 예시 (a, b 비교)

#include <stdio.h>

int main()
{
    int a = 2;
    int b = 6;
    printf("d\n", a == b);  // false
    printf("d\n", a != b);  // true
    printf("d\n", a > b);  // false
    printf("d\n", a >= b);  // false
    printf("d\n", a < b);  // true
    printf("d\n", a <= b);  // true
    
    return 0;
}

▽ 출력 결과

0
1
0
0
1
1

6. 논리 연산자(Logical Operators)

해당 논리식의 참(true)과 거짓(false)을 결정하는 연산자

• `!` : 단항 연산자

• `&&`, `||` : 이항 연산자

true
int d = true; // d는 1

• 0이 아닌 모든 수
주로 1로 표현
false
int e = false; // e는 0

• 0

• 논리 연산자가 사용되는 경우 : if문, while문, do-while문, for문, 삼항 연산자, 함수 인자, 논리 연산의 결괏값을 변수에 할당하는 등

참, 거짓 전용 자료형 : bool(1byte)

C에는 없던 `bool`형과 bool형에서의 true, false가 C++에서 추가됐다.

bool isTrue = true;  // true
bool isFalse = false;  // false

true일 때 bool 자료형에 1 말고 다른 정수를 넣어도 1로 변환돼서 들어간다.

bool tf1 = -100;  // true

논리 연산자 설명 예시
!
(NOT, 부정)
bool tf1 = true; // tf1은 true
tf1 = !tf1; // tf1은 false

• 해당 결과가 참이면 0, 거짓이면 1 반환
int tf2 = 100; // tf2는 100
tf2 = !tf2; // tf2는 0

논리 연산자를 사용해서 true, false를 따질 때
꼭 bool만 쓰는 것은 아니다.
&&
(AND, 논리곱)

둘 다 참이면 1 반환

int tf3;
tf3 = 100 &amp;&amp; 200; // tf3은 1
int tf3;
tf3 = 0 &amp;&amp; 200; // tf3는 0
||
(OR, 논리합)
'|' 쓰는 법 : Shift + \

• 둘 중 하나라도 참이면 1 반환
int tf4;
tf4 = 0 ❘❘ 100; // tf4는 1
int tf4;
tf4 = 0 ❘❘ 0; // tf4는 0

7. 비트 연산자(Bitwise Operators)

비트(bit) 단위로 연산이 진행될 때 사용하는 이항 연산자

비트 연산자 설명
<<
(left shift 연산자)
• 지정한 수만큼 비트를 전부 왼쪽으로 이동시킨다.
>>
(right shift 연산자)
부호는 유지하면서 지정한 수만큼 비트를 전부 오른쪽으로 이동시킨다.
&
(비트 AND 연산자)
둘 다 1이면 ➜ 1
• 둘 중 하나라도 0이면 ➜ 0
|
(비트 OR 연산자)
둘 중 하나라도 1이면 ➜ 1
~
(비트 NOT 연산자)
• 비트가 1이면 ➜ 0
• 비트가 0이면 ➜ 1
^
(비트 XOR 연산자)
• 두 비트가 같으면 ➜ 0
• 두 비트가 다르면 ➜ 1

1. shift 연산자

1) `<<` (left shift)

2진수 : 한 칸 올라간다. = 한 칸 왼쪽으로 간다. = 2배 증가

10진수 : 자릿 수가 하나 증가한다. (ex. 일의 자리에서 십의 자리로) = 10배 증가

 

▷ 10을 왼쪽으로 1칸 이동

unsigned char byte = 10;
// 왼쪽으로 한 칸 이동
byte <<= 1;  // 20
// byte → 10 × 2^1 = 10 × 2 = 20

`byte <<= 1`는 `byte = byte << 1`을 축약해서 표현한 것이다.

0 0 0 0 1 0 1 0

= 10

0 0 0 1 0 1 0 0

= 20

 

▷ 10을 왼쪽으로 2칸 이동

unsigned char byte = 10;
// 왼쪽으로 2칸 이동
byte <<= 2;  // 40
// byte → 10 × 2^2 = 10 × 4 = 40

 

왼쪽으로 2칸 밀면 2^2=4배, 3칸 밀면 2^3=8배

왼쪽으로 n칸 밀면 2^n배

 

2) `>>` (right shift)

2진수 : 한 칸 내려간다. = 한 칸 오른쪽으로 간다. = 1/2로 감소

10진수 : 자릿 수가 하나 감소한다. (ex. 십의 자리에서 일의 자리로) = 1/10로 감소

 

▷ 13을 오른쪽으로 1칸 이동

unsigned char byte = 13;
// 오른쪽으로 1칸 이동
byte >>= 1;  // 6
// byte → 13 ÷ 2^1 = 13 ÷ 2 = 6(몫)

 

홀수 ÷ 2 했을 때 나머지는 생각할 필요가 없다.

비트를 오른쪽으로 옮기고 그 결괏값인 을 다시 변수에 넣기 때문이다.

0 0 0 0 1 1 0 1

= 13

0 0 0 0 0 1 1 0

= 6

 

▷ 13을 오른쪽으로 2칸 이동

unsigned char byte = 13;
// 오른쪽으로 2칸 이동
byte >>= 2;  // 3
// byte → 13 ÷ 2^2 = 13 ÷ 4 = 3(몫)

 

오른쪽으로 2칸 밀면 2^2=4로 나눈 몫, 3칸 밀면 2^3=8로 나눈 몫

∴ 오른쪽으로 n칸 밀면 2^n로 나눈 몫


2. & (비트 AND(곱) 연산자)

• 둘 다 1이면 ➜ 1

둘 중 하나라도 0이면 ➜ 0

0 & 0 0
0 & 1 0
1 & 0 0
1 & 1 1

3. | (비트 OR(합) 연산자)

• 둘 중 하나라도 1이면 ➜ 1

0 | 0 0
0 | 1 1
1 | 0 1
1 | 1 1

4. ~ (비트 NOT 연산자)

• 비트가 1이면 ➜ 0

• 비트가 0이면 ➜ 1

~ 0 1
~ 1 0

5. ^ (비트 XOR 연산자)

• 두 비트가 같으면 ➜ 0

• 두 비트가 다르면 ➜ 1

0 ^ 0 0
0 ^ 1 1
1 ^ 0 1
1 ^ 1 0

전처리기

컴파일하기 전에 가장 먼저 수행된다.

앞에 `#`이 붙는다.


#define

내가 지정한 구문을 특정 문자 · 숫자로 치환해 준다.

• 함수처럼 사용할 수 있다.

`#define` 장점

ex) TIRED을 1로 정의해라.

#include <iostream>

#define TIRED 1  // TIRED를 1로 정의
// 보통 캐릭터가 보유하고 있는 상태는 여러 가지이다. (ex. 배고픔, 지침, 공격력 버프, 독 중독 상태 등)
// 각종 상태들은 중첩돼서 돌아간다.

using std::cout;

int main()
{  
    int Status01 = TIRED;
    cout << Status01;  // 1
    
    return 0;
}

▽ 출력 결과

1

1) 가독성이 좋다.

1은 지친 상태라는 것을 딱 보면 바로 알 수 있다.

숫자가 아니라 명확하게 문자로 적기 때문에 외울 필요도 없다.

 

2) 전처리기로 코드 유지보수 관리가 용이하다.

전처리기로 설정한 값을 수정해야 할 때 전체 코드에서 해당 부분을 찾아가면서 일일이 다 바꿀 필요가 없다.

문자로 지정해 놨기 때문에 `#define` 부분만 수정하면 된다.

#include <iostream>

#define TIRED 10  // TIRED 정의한 부분에서 1을 10으로 바꾸기만 하면 된다.

using std::cout;

int main()
{
    int Status01 = TIRED;
    cout << Status01;  // 10
    
    return 0;
}

▽ 출력 결과

10

비트 연산자 활용 예시

int(32bit)를 이용해서 특정 상태를 표현하기

표현할 수 있는 경우의 수(가지 수)를 말하는 것이 아니다.

#define TIRED 1
#define HUNGRY 2
#define DIZZY 4

상태는 조합이 될 수 있어야 한다.

조합 : 중복 X, 순서 상관 X

하나의 변수가 특정 경우가 아닌 여러 종류의 상태를 표현하려면 겹치지 않는 자리가 필요하다.

비트 자리에 따라 상태를 다르게 하여 각각의 상태가 담당하는 자리를 하나씩 가지게 된다면 총 32개의 상태를 한 번에 나타낼 수 있다.

∴ unsigned int 32bit 변수로 동시에 표현할 수 있는 상태는 32가지이다.


1) 비트 OR 연산자로 비트 합치기

unsigned int iStatus = 0;
iStatus |= TIRED;  // 지침
iStatus |= HUNGRY;  // 지침 + 배고픔
iStatus |= DIZZY;  // 지침 + 배고픔 + 어지러움

`|=` : 비트를 합쳐서 다시 변수에 넣는다.

        1 = 어지러운 상태
또는
0 = 어지럽지 않은 상태
1 = 배고픈 상태
또는
0 = 배고프지 않은 상태
1 = 지친 상태
또는
0 = 지치지 않은 상태
        2^2 = 4
(DIZZY = 4)
2^1 = 2
(HUNGRY = 2)
2^0 = 1
(TIRED = 1)

2) 비트 AND 연산자로 비트 검사하기

// 상태 체크
if (iStatus & HUNGRY)
{
	// 배고픈 상태(HUNGRY)라면 이 부분 실행
}

`&` : 둘 다 1일 때만 1

3) 비트 XOR 연산자(같으면 0, 다르면 1)로 특정 자리에 있는 비트 빼기 (`1` → `0`)

제거하고 싶은 비트 자리에 1을 넣고 비트 XOR 연산자로 연산한다.

ex) `1101`에서 `1001`로 바꾸고 싶은 경우

  1101
^ 0100
========
  1001

비트 XOR 연산자로 비트를 뺄 때 발생하는 문제

애초에 캐릭터가 지친 적이 없다면 그 자리는 0이므로 XOR로 연산하면 오히려 1이 되어버린다.

  1100
^ 0001
========
  1101

비트에서 특정 자리를 뺄 때 비트가 있으면 빼고 없으면 없는 상태여야 한다.

비트를 뺄 때 쓰는 다른 방법

// 이 형태 기억하기
Status01 &= ~HUNGRY;

상태변수 &= ~상태;

제거하고 싶은 자리에 1을 넣고 `~`(비트 NOT 연산자)를 이용하여 반전시킨다.

원래 있던 상태 변수에 `&`(곱연산)을 한다.

 

▷ 제거하고 싶은 자리가 처음부터 1일 때 : `1110 1010`

① 제거하고 싶은 자리에 1을 넣고 `~`(비트 NOT 연산자)로 반전시킨다.

0000 0010
    ↓
1111 1101

 

② 원래 비트와 `~`(비트 NOT 연산자)로 반전시킨 비트를 `&`(비트 AND 연산자)로 서로 곱한다.

  1110 1010
& 1111 1101
=============
  1110 1000

`1110 1010` → `1110 1000`

원래 비트에서 빼려고 했던 자리만 0으로 바뀌었다.

 

▷ 제거하고 싶은 자리가 처음부터 0일 때 : `1110 1000`

① 제거하고 싶은 자리에 1을 넣고 `~`(비트 NOT 연산자)로 반전시킨다.

0000 0010
    ↓
1111 1101

 

② 원래 비트와 `~`(비트 NOT 연산자)로 반전시킨 비트를 `&`(비트 AND 연산자)로 서로 곱한다.

  1110 1000
& 1111 1101
=============
  1110 1000

`1110 1000` → `1110 1000`

원래 비트에서 빼려고 했던 자리가 0이므로 1로 바뀌는 문제없이 그대로 0이다.


#define 상태값

• `#define` 뒤에 상태값은 대부분 16진수로 작성한다.

16진수는 앞에 `0x`가 붙는다.

 

10진수에서 10개가 모여야 다음 자리로 넘어가듯이 16진수에서는 16개야 모여야 다음 자리로 넘어간다.

16진수에서 16 : 0x10

16진수에서 32 : 0x20 (32는 16이 2개 모여야 되기 때문)

#define TIRED 0x1  // 1
#define HUNGRY 0x2  // 2
#define DIZZY 0x4  // 4
#define CONFUSE 0x8  // 8

#define BLEED 0x10  // 16
#define STUN 0x20  // 32
#define FREEZE 0x40  // 64
#define BURN 0x80  // 128

#define POISON 0x100  // 256
#define SILENCE 0x200  // 512
#define RECOVERY 0x400  // 1024
#define DOT 0x800  // 2048

// ======================== //
// 자릿수 맞춰서 작성한 코드
// ======================== //
#define TIRED     0x1  // 1
#define HUNGRY    0x2  // 2
#define DIZZY     0x4  // 4
#define CONFUSE   0x8  // 8

#define BLEED     0x10  // 16
#define STUN      0x20  // 32
#define FREEZE    0x40  // 64
#define BURN      0x80  // 128

#define POISON    0x100  // 256
#define SILENCE   0x200  // 512
#define RECOVERY  0x400  // 1024
#define DOT       0x800  // 2048

연산자 우선순위(Operator Precedence)

• 피연산자를 계산하는 순서

우선순위 연산자 설명 결합 방향
1 :: 범위 지정 연산자
(C++만 해당)
없음.
2 ++ 후위 증가 연산자
  -- 후위 감소 연산자
  ( ) 함수 호출
  [ ] 첨자 연산자
  . 멤버 연산자
  -> 멤버 접근 연산자
  typeid() 타입 인식
  const_cast 상수 타입 변환
  dynamic_cast 동적 타입 변환
  reinterpret_cast 재해석 타입 변환
  static_cast 정적 타입 변환
3 ++ 전위 증가 연산자
  -- 전위 감소 연산자
  + 양의 부호
(단항 연산자)
  - 음의 부호
(단항 연산자)
  ! 논리 NOT 연산자
  ~ 비트 NOT 연산자
  (type) 타입 캐스트 연산자
  * 참조 연산자
(단항 연산자)
  & 주소 연산자
(단항 연산자)
  sizeof 크기 연산자
  _Alignof 정렬 요구사항
(C++ 11부터)
  new, new[ ] 객체 생성
  delete, delete[ ] 객체 제거
4 .* 멤버 포인터 연산자
  ->* 참조 멤버 포인터 연산자
5 * 곱셈 연산자
  / 나눗셈 연산자
  % 나머지 연산자
6 + 덧셈 연산자
(이항 연산자)
  - 뺄셈 연산자
(이항 연산자)
7 << 비트 왼쪽 shift 연산자
  >> 비트 오른쪽 shift 연산자
8 <=> 3방향 비교
(C++ 20에서 도입, C++만 해당)
9 < 관계 연산자
(~보다 작은)
  <= 관계 연산자
(~보다 작거나 같은)
  > 관계 연산자
(~보다 큰)
  >= 관계 연산자
(~보다 크거나 같은)
10 == 관계 연산자
(~와 같은)
  != 관계 연산자
(~와 같지 않은)
11 & 비트 AND 연산자
12 ^ 비트 XOR 연산자
13 | 비트 OR 연산자
14 && 논리 AND 연산자
15 || 논리 OR 연산자
16 co_await 코루틴 처리
(C++만 해당)
  co_yield 코루틴 처리
(C++만 해당)
17 ?: 삼항 조건 연산자
18 = 대입 연산자
(할당)
  += 복합 대입 연산자
(덧셈 후 할당)
  -= 복합 대입 연산자
(뺄셈 후 할당)
  *= 복합 대입 연산자
(곱셈 후 할당)
  /= 복합 대입 연산자
(나눗셈 후 할당)
  %= 복합 대입 연산자
(나머지 연산 후 할당)
  <<= 복합 대입 연산자
(비트를 왼쪽으로 shift한 후 할당)
  >>= 복합 대입 연산자
(비트를 오른쪽으로 shift한 후 할당)
  &= 복합 대입 연산자
(비트 AND 연산 후 할당)
  ^= 복합 대입 연산자
(비트 XOR 연산 후 할당)
  |= 복합 대입 연산자
(비트 OR 연산 후 할당)
19 throw 예외 발생
20 , 쉼표 연산자