연산자와 형변환
값을 셈하고 견주는 기호들과, 타입을 바꿔 담는 방법입니다.
값을 셈하고 견주는 기호들
연산자(operator)는 값을 가지고 무언가를 하라는 기호입니다. 더하고 빼는 것부터 두 값이 같은지 견주는 것까지, 프로그램이 하는 일의 대부분은 연산자로 적힙니다.
연산자는 하는 일에 따라 몇 가지로 나뉩니다.
- 산술 — 더하기·빼기처럼 셈을 합니다.
+ - * / % - 비교 — 두 값을 견주어 참·거짓을 냅니다.
== != > < >= <= - 논리 — 참·거짓끼리 묶습니다.
&& || ! - 대입 — 값을 담습니다.
= += -= *= /= - 비트 — 숫자를 이진수 자리로 펼쳐 셈합니다.
& | ^ ~ << >>
그리고 타입이 서로 다른 값을 함께 셈하려면 한쪽을 다른 쪽 타입으로 바꿔야 합니다. 이것을 형변환(type conversion)이라고 합니다. C#이 알아서 바꿔 주는 경우도 있고, 우리가 직접 밝혀야 하는 경우도 있습니다.
정수끼리 나누면 소수점이 사라집니다
아래 코드는 브라우저 안에서 실제로 실행됩니다. 결과를 먼저 짐작해보고 눌러서 맞는지 확인해보세요.
int a = 7, b = 2; Console.WriteLine(a / b); // 몫만 남습니다 Console.WriteLine(a % b); // 나머지 Console.WriteLine((double)a / b); // 한쪽을 실수로
코드는 고쳐서 실행해 볼 수 있습니다. 처음 누를 때만 실행기를 내려받느라 잠시 걸립니다. 적은 코드는 서버로 나가지 않습니다.
7 / 2 가 3.5가 아니라 3인 것이 처음에는
뜻밖일 수 있습니다. 정수끼리 나누면 결과도 정수여야 하므로 소수점 아래가 버려집니다.
소수점까지 필요하면 한쪽을 실수로 바꿔야 하고, 그 방법이 위의
(double) 입니다.
자주 사용하는 연산자
| 연산자 | 하는 일 | 예시 |
|---|---|---|
| + - * / | 더하기·빼기·곱하기·나누기 | 10 * 3 → 30 |
| % | 나눈 나머지 | 10 % 3 → 1 |
| += -= | 지금 값에 더하거나 뺀 뒤 다시 담기 | count += 5; |
| ++ -- | 1 만큼 늘리거나 줄이기 | count++; |
| == != | 같은지 · 다른지 | age == 20 |
| && || | 그리고 · 또는 | age >= 20 && isMember |
| ! | 참·거짓 뒤집기 | !isStudent |
+ 는 문자열에도 쓰이는데, 이때는 셈이 아니라 이어 붙이기가
됩니다. "3" + "4" 는 7이 아니라
"34" 입니다.
&& 와 || 는 결과가
정해지면 뒤를 보지 않습니다. false && ... 는 뒤가
무엇이든 거짓이므로 오른쪽을 아예 실행하지 않습니다. 이것을
단축 평가라고 하며, 앞에서 조건을 걸러 뒤가 안전할 때만 실행하게 하는
데 자주 사용됩니다.
비트 연산자
숫자를 이진수로 펼쳐 자리마다 셈하는 연산자도 있습니다. 셈을 하려고 쓰기보다는 켜짐·꺼짐 여러 개를 정수 하나에 담을 때 주로 만나게 됩니다. 권한 목록이나 설정 묶음을 이렇게 다루며, 2부에서 배울 플래그 열거형이 바로 그 방식입니다.
| 연산자 | 하는 일 | 예시 (6은 110, 3은 011) |
|---|---|---|
| & | 양쪽 자리가 모두 1이면 1 | 6 & 3 → 2 |
| | | 한쪽이라도 1이면 1 | 6 | 3 → 7 |
| ^ | 두 자리가 서로 다르면 1 | 6 ^ 3 → 5 |
| ~ | 모든 자리를 뒤집기 | ~6 → -7 |
| << >> | 자리를 왼쪽·오른쪽으로 밀기 | 1 << 3 → 8 |
& 와 && 는 글자가
비슷하지만 하는 일이 다릅니다. && 는 참·거짓을
묶고 앞에서 판가름 나면 뒤를 보지 않지만, & 는 자리마다
셈하며 양쪽을 모두 봅니다. 참·거짓을 다룰 때는
&& 와 || 를 사용하세요.
타입을 바꾸는 두 가지 길
담을 형식의 범위가 넉넉하면 C#이 알아서 바꿔 줍니다(암시적 변환).
int 를 double 에 담는 것처럼
값이 잘려 나갈 일이 없는 방향입니다. 반대로 범위가 좁은 형식에 담을 때는 잃는 것이 생기므로
직접 밝혀야 합니다.
int n = 10; double d = n; // 암시적 — 그냥 담깁니다 double pi = 3.9; int m = (int)pi; // 명시적 — (int) 로 밝힙니다
여기서 (int)3.9 의 결과가 4가 아니라
3이라는 점을 눈여겨보세요. 캐스트는 반올림이 아니라 소수점 아래를
버립니다. 반올림하려면 Convert 를
사용합니다.
int a = (int)3.9; // a 는 3 int b = (int)3.2; // b 는 3
int a = Convert.ToInt32(3.9); // a 는 4 int b = Convert.ToInt32(3.2); // b 는 3
문자열을 숫자로 바꾸기
사람이 입력한 값은 문자열로 들어옵니다. 그것으로 셈을 하려면 숫자로 바꿔야 하는데,
바꿀 수 없는 값이 들어올 수 있다는 점이 중요합니다.
Parse 는 그럴 때 예외를 던지며 멈추고,
TryParse 는 멈추지 않고 실패했다고 알려 줍니다.
int n = int.Parse("123"); // 123 — "abc" 였다면 예외 if (int.TryParse("abc", out int m)) { Console.WriteLine(m); } else { Console.WriteLine("숫자가 아닙니다"); // 이쪽으로 옵니다 }
사람이 넣는 값을 다룰 때는 TryParse 를 사용하세요.
오타 하나로 프로그램이 멈추는 일을 막아 줍니다. 반대로 숫자를 문자열로 바꾸는 것은
언제나 되므로 ToString() 하나로 끝납니다.
이 문법, 몇 버전부터 사용할 수 있나요
- 1.0산술 · 비교 · 논리 연산자, 캐스트
- 2.0?? — null 이면 다른 값을 사용하는 연산자
- 6.0?. — null 이면 건너뛰는 연산자
- 8.0??= — null 일 때만 담는 대입
이 단원의 연산자와 캐스트는 C# 1.0부터 있던 것이라 버전을 가리지 않습니다.
다만 값이 없을 수 있는(null) 자리를 다루는 연산자들은 뒤에 하나씩 더해졌습니다.
?? 는 왼쪽이 null 이면 오른쪽 값을 사용하고,
?. 는 앞이 null 이면 뒤를 실행하지 않고 넘어갑니다.
지금은 이런 것이 있다는 정도만 알아 두고, 자세한 것은 2부에서 클래스와
참조 형식을 배운 뒤에 다시 보면 됩니다.
직접 해보기
int total = 137; 을 두고, 이것이 몇 분 몇 초인지
계산해 2분 17초 형태로 출력해보세요.
string input = "3.5"; 를 두고, 이것을
double 로 바꿀 수 있으면 2를 곱해 출력하고, 바꿀 수
없으면 안내 문구를 출력해보세요. 프로그램이 멈추지 않아야 합니다.
- 정수끼리 나누면 몫만 남습니다. 소수점이 필요하면 한쪽을 실수로 바꿉니다.
%는 나머지를 냅니다. 몫과 짝으로 자주 쓰입니다.- 캐스트
(int)는 소수점 아래를 버리고,Convert는 반올림합니다. - 사람이 넣는 값은
TryParse로 받습니다. 실패해도 멈추지 않습니다.
C# 버전별 변경 이력 에서 각 버전이 무엇을 더했는지 볼 수 있습니다.