Menu

C# 연산자: 산술, 나머지, 논리, 비트 연산자와 우선순위

C# 연산자의 정확한 동작: 정수 나눗셈, 음수에서의 나머지 연산자, 증감 연산자와 복합 대입, 비교, 단락 평가 논리 연산, 비트 연산자, null 연산자, 우선순위 표를 정리합니다.

이 페이지에는 실행 가능한 에디터가 있습니다 - 편집하고 실행하면 결과를 바로 볼 수 있습니다.

연산자는 피연산자 하나, 둘 또는 셋을 받아 값을 만듭니다: a + b, !done, x ?? fallback. C# 연산자는 C, Java, JavaScript의 연산자와 비슷하지만, 몇몇은 처음 배우는 사람을 놀라게 하는 방식으로 동작합니다. 무엇보다 정수 나눗셈과 %의 부호가 그렇습니다.

산술 연산자

+, -, *, /, %는 모든 숫자 타입에 동작합니다. 결과 타입은 피연산자를 따릅니다. int 두 개는 int를, int와 double은 double을 만듭니다.

출력:

22
12
85
3
2
3.4
3.4
3
3.4

정수 나눗셈은 0 방향으로 잘라냅니다. 17 / 5는 3이고 -17 / 5는 -3입니다. 이것이 아주 흔한 버그를 만듭니다. int percent = done / total * 100;은 done < total이면 항상 0입니다. done / total이 이미 0이기 때문입니다. 곱셈을 먼저 하거나(done * 100 / total) double로 나누세요.

정수나 decimal을 0으로 나누면 DivideByZeroException이 발생합니다. double을 0으로 나누면 예외가 아니라 무한대가 되고, 0.0 / 0.0이면 NaN이 됩니다:

출력:

True
True
False
DivideByZeroException

나머지 연산자와 음수

%는 나눗셈의 나머지를 반환하며, 결과는 왼쪽 피연산자의 부호를 따릅니다. 이는 양수로 나누면 항상 0 이상인 Python이나 수학의 "mod"와 다릅니다:

출력:

1
-1
1
2
even
62 min 5 s
Thu
1.5

왼쪽이 음수가 될 수 있고 결과를 인덱스로 쓸 때는 언제나 Mod 헬퍼를 쓰세요. days[(today + offset) % 7]은 합이 음수이면 IndexOutOfRangeException을 던집니다. 홀수 검사에도 같은 함정이 있습니다. n % 2 == 1은 음의 홀수에서 false이므로 n % 2 != 0으로 검사하세요.

대입, 복합 대입, 증감

=는 대입합니다. 복합 형태 +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=는 연산과 대입을 합칩니다. ++와 --는 1을 더하거나 빼며, 반환하는 값이 다른 전위형과 후위형이 있습니다:

출력:

14
start, step
a=5 b=7 i=7
4

byte 사례는 특이한 점을 보여 줍니다. byte + int는 int이므로 level = level + 10;은 컴파일되지 않지만, 복합 대입에는 변수 타입으로의 암시적 캐스트가 포함되어 있으므로 level += 10;은 컴파일됩니다. 이 캐스트는 오버플로 시 값이 돌아갑니다(250 + 10이 4가 됩니다).

비교 연산자와 논리 연산자

비교 연산자(==, !=, <, >, <=, >=)는 bool을 반환합니다. 문자열에서 ==는 참조가 아니라 텍스트를 비교합니다. 논리 연산자는 !(not), &&(and), ||(or), ^(배타적 or)입니다.

출력:

True
no active user
with ||:
  evaluated A
with |:
  evaluated A
  evaluated B
True

&&와 ||는 단락 평가를 합니다. 오른쪽 피연산자는 결과를 바꿀 수 있을 때만 실행됩니다. 그래서 user != null && user.IsActive가 안전합니다. 불리언에 쓰는 한 글자 &와 |는 항상 양쪽을 평가하며, 조건에서 원하는 동작인 경우는 드뭅니다.

비트 연산자와 시프트 연산자

정수 타입에서 &, |, ^, ~는 개별 비트에 동작하고, <<와 >>는 비트를 이동시킵니다. 플래그, 마스크, 해싱, 저수준 프로토콜에 쓰입니다:

출력:

3
True
False
101
1024
125
5
-1

이름 붙은 플래그 집합에는 정수 상수보다 [Flags] 특성을 붙인 열거형이 더 명확하고, 마스크보다 HasFlag가 더 읽기 좋습니다. C# 11은 음수에서도 0으로 채우는 부호 없는 오른쪽 시프트 >>>를 추가했습니다.

null 연산자

null일 수 있는 값을 다루기 위한 연산자가 세 가지 있습니다:

출력:

Guest

0
5

a ?? b는 a가 null이 아니면 a를, null이면 b를 반환합니다. a?.Member는 a가 null이면 예외 대신 null을 반환합니다. C# 8은 a가 null일 때만 a에 b를 대입하는 a ??= b를 추가했습니다. 자세한 내용은 nullable 형식에서 다룹니다.

연산자 우선순위

식에 여러 연산자가 섞이면 위쪽 행이 더 강하게 결합합니다. 같은 행의 연산자는 왼쪽에서 오른쪽으로 묶이지만, 대입, ??, ?:는 오른쪽에서 왼쪽으로 묶입니다. (피연산자 자체는 항상 왼쪽부터 평가됩니다.)

분류연산자
기본x.y, x?.y, f(x), a[i], x++, x--, new, typeof, nameof
단항+x, -x, !x, ~x, ++x, --x, (T)x, await
곱셈*, /, %
덧셈+, -
시프트<<, >>, >>>
관계와 타입 검사<, >, <=, >=, is, as
같음==, !=
비트 AND&
비트 XOR^
비트 OR|
조건부 AND&&
조건부 OR||
null 병합??
조건c ? a : b
대입과 람다=, +=, -=, ??=, =>, 그 밖의 복합 형태

알아 둘 결과가 두 가지 있습니다. a + b * c는 곱셈을 먼저 하고, x & mask == 0은 비교를 먼저 합니다(==가 &보다 강하게 결합). 그래서 x & (mask == 0)이라는 뜻이 되고 정수에서는 컴파일되지 않습니다. (x & mask) == 0이라고 쓰세요. 괄호는 비용이 없고 의도를 분명하게 합니다.

연산자 오버로딩

직접 만든 타입에서 연산자의 의미를 정의할 수 있습니다. decimal, DateTime, TimeSpan이 +와 <를 지원하는 방법이 이것입니다:

출력:

33.49
True

연산자는 public static이어야 하고, 일부는 반드시 짝으로 정의해야 합니다. <를 정의하면 >가, ==를 정의하면 !=가 필요합니다. ==를 정의하면 이에 맞게 Equals와 GetHashCode를 재정의할 때까지 컴파일러가 경고합니다. 숫자, 벡터, 금액처럼 의미가 분명한 곳에서만 연산자를 오버로딩하세요.

자주 묻는 질문

C#에서 %는 무엇을 하나요?

%는 나머지 연산자입니다. 17 % 5는 2입니다. 결과는 왼쪽 피연산자의 부호를 따르므로 -7 % 3은 Python처럼 2가 아니라 -1입니다. 인덱스를 순환시킬 때처럼 항상 0 이상인 결과가 필요하면 ((a % n) + n) % n이라고 쓰세요. double과 decimal에도 동작합니다: 7.5 % 2는 1.5입니다.

C#에서 7 / 2가 3인 이유는 무엇인가요?

두 피연산자가 모두 정수이면 /는 정수 나눗셈을 하고 소수 부분을 0 방향으로 잘라 버립니다. 소수 결과를 얻으려면 피연산자 하나를 부동소수점이나 decimal 값으로 만드세요. 7 / 2.0은 3.5, (double)a / b는 나누기 전에 변환하고, 7m / 2는 decimal 3.5입니다.

C#에서 &&와 &의 차이는 무엇인가요?

&&는 조건부 AND로, 왼쪽이 false이면 오른쪽을 평가하지 않습니다. 불리언에 쓴 &는 항상 양쪽을 평가하고, 정수에 쓰면 비트 AND입니다. 조건에는 &&와 ||를 쓰세요. 특히 user != null && user.IsActive 같은 보호 조건은 &로 쓰면 NullReferenceException을 던집니다.

C#에서 i++와 ++i의 차이는 무엇인가요?

둘 다 i에 1을 더합니다. 식 i++는 이전 값으로, ++i는 새 값으로 평가됩니다. 한 줄에 단독으로 쓰면(i++;) 차이가 없습니다. int a = i++;처럼 결과를 사용할 때만 차이가 나므로, 많은 스타일 가이드가 증감을 별도 줄에 두라고 합니다.

C#의 연산자 우선순위는 어떻게 되나요?

높은 것부터 낮은 순서로: 기본(x.y, f(x), a[i], x++), 단항(!, -, ++x, 캐스트), 곱셈(* / %), 덧셈(+ -), 시프트, 관계(< > <= >= is as), 같음(== !=), &, ^, |, &&, ||, ??, 조건 ?:, 마지막으로 대입입니다. 확실하지 않으면 괄호를 추가하세요.

Coddy programming languages illustration

Coddy로 코딩 배우기

시작하기