1. 산술 연산자
숫자 형식의 데이터에 사용 가능한 산술 연산자로는 다음과 같은 것들이 있으며 계산방식은 일반적인 수학 연산과 거의 동일합니다.
| 연산자 | 기능 |
| + | 더하기 |
| - | 빼기 |
| * | 곱하기 |
| / | 나누기 |
| % | 나머지 |
static void Main(string[] args)
{
int i = 10;
int j = 20;
int s = i + j; //+ 연산자
WriteLine(s);
}
● 문자열 결합
산술 연산자 중 + 연산자는 다음과 같이 문자열 결합에도 사용할 수 있습니다.
static void Main(string[] args)
{
string s1 = "123";
string s2 = "456";
WriteLine(s1 + s2);
}
문자열은 서로 연산하지 않고 단순히 결합되므로 위의 예제는 "123456"이라는 결과를 표시하게 됩니다.
2. 증가/감소 연산자
| 연산자 | 기능 |
| ++ | 피연산자를 1증가시킵니다. |
| -- | 피연산자를 1감소시킵니다. |
산술 연산자는 피연산자를 2개(이항 연산자) 이상 필요로 하지만 증가/감소 연산자는 단 하나의 연산자(단항 연산자)만을 필요로 합니다.
증가/감소 연산자가 피연산자의 앞에 오는 경우(전위 연산자) 해당 문장이 평가되기 전에 연산자부터 먼저 실행되지만 피연산자의 뒤에 오는 경우(후위 연산자)는 해당 문장이 평가된 후에 실행됩니다.
static void Main(string[] args)
{
int i = 10;
int j = 20;
WriteLine(++i); //11 출력
WriteLine(j++); //20 출력 -> 실제값 21
}
따라서 같은 연산자를 사용했더라도 연산자의 위치에 따라 값이 달라질 수 있으므로 주의가 필요합니다.
3. 관계 연산자
관계 연산자는 두 피연산자 사이의 관계를 나타냅니다.
| 연산자 | 기능 (왼쪽 피연산자 기준) |
| < | 작다. |
| > | 크다. |
| <= | 작거나 같다. |
| >= | 크거나 같다. |
| == | 같다. |
| != | 같지 않다. |
상기 모든 관계 연산자는 조건에 따라 결과로 bool형식을 반환합니다.
static void Main(string[] args)
{
int i = 10;
int j = 20;
WriteLine(i < j); //i가 j보다 작으므로 true
WriteLine(j < i); //j가 i보다 크므로 false
WriteLine(i != j); //i와 j는 같지 않으므로 true
}
4. 논리 연산자
논리 연산자는 참/거짓을 피연산자로 하여 평가하는 연산자이며 다음과 같은 연산자가 존재합니다.
| 연산자 | 기능 |
| && | 피연산자가 모두 참인 경우에만 참(논리곱 연산자) |
| || | 피연산자중 하나라도 참인 경우에만 참(논리합 연산자) |
| ! | 피연산자를 반대로 하여 평가(부정) |
static void Main(string[] args)
{
bool b1 = true;
bool b2 = false;
WriteLine(b1 && b2); //모두 true가 아니므로 false
WriteLine(b1 || b2); //하나가 true이므로 true
WriteLine(!b1); //b1이 true이므로 false
}
5. 조건 연산자
필요한 피연산자가 3개가 되는 연산자라고 해서 '삼항 연산자'라고도 하며 첫 번째 연산자의 참/거짓에 따라 두번째 혹은 세번째 식이 실행되는 연산자입니다.
static void Main(string[] args)
{
bool b = true;
var result = (b ? "b는 true" : "b는 false"); //b는 true 이므로 ? 다음 두번째 피연산자가 실행
WriteLine(result);
}
첫 번째 피연산자 다음 ? 문자로 두 번째 피연산자를, 그 다음 : 문자로 세 번째 피연산자를 지정합니다. 이 후 첫번째 피연산자의 상태값에 따라 true면 ? 다음 두번째 연산자가, false면 : 다음 세번째 피연산자를 실행합니다.
6. null 조건부 연산자
피연산자의 null(아무 값도 가지지 않은 상태) 상태를 확인하고 null이면 null을 아니면 지정한 멤버 값을 가져오는 연산자입니다.
using System;
using static System.Console;
namespace Test
{
class Test
{
public int member;
}
class MyTestApp
{
static void Main(string[] args)
{
Test test = null;
int? member = null;
//null 조건 연산자를 사용하지 않는 경우
if (test == null)
member = null;
else
member = test.member;
//null 조건 연산자를 사용하는 경우
member = test?.member;
//결과
WriteLine(member);
}
}
}
null 조건부 연산자는 또한 배열 같은 컬렉션 객체에서도 적용됩니다.
using System;
using System.Collections;
using static System.Console;
namespace Test
{
class MyTestApp
{
static void Main(string[] args)
{
ArrayList a = null;
a?.Add(100); //a가 null이므로 add() 메서드는 호출불가
WriteLine(a?[0]); //a가 여전히 null이므로 아무런 내용도 출력하지 않음
}
}
}
7. 비트 연산자
비트(bit) 단위의 연산을 수행하는 연산자입니다.
● 시프트 연산자
시프트 연산자는 다음과 같은 2개의 연산자가 있으며 비트를 직접적으로 이동시키는 연산자입니다.
| << | 피연산자의 비트를 지정한 수만큼 왼쪽으로 이동 |
| >> | 피연산자의 비트를 지정한 수만큼 오른쪽으로 이동 |
아래 예제는 byte형 변수 b에 1 값을 저장하고 있습니다.
static void Main(string[] args)
{
byte b = 1;
WriteLine(b);
}
그러면 변수 b는 내부적으로 다음과 같은 비트를 유지하게 됩니다.
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
이 상태에서 변수 b에 비트 연산자를 적용시키게 되면
static void Main(string[] args)
{
byte b = 1;
WriteLine(b << 1);
}
bit를 1만큼 왼쪽으로 밀게 되고 밀려난 자리는 0으로 채워지게 됩니다.(단, 음수의 경우에는 1로 채움)
| 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
따라서 예제의 결과는 2를 표시합니다.
● 비트 논리 연산자
각 비트에 대해 논리적 연산을 수행하는 것으로 다음과 같은 연산자가 존재합니다.
| & | 피연산자의 비트에 논리곱 연산을 수행합니다. |
| | | 피연산자의 비트에 논리합 연산을 수행합니다. |
| ^ | 피연산자의 비트에 베타적 논리합 연산을 수행합니다. |
| ~ | 피연산자의 비트를 반전시킵니다. |
이때 각 비트에서 0은 false로 1은 true로 취급되며 논리곱은 피연산자 모두 true여야만 true를, 논리합은 피연산자 중 하나만이라도 true면 true를, 배타적 논리합은 피연산자의 상태가 서로 다 달라야만 true를 반환합니다.
static void Main(string[] args)
{
byte b1 = 1;
byte b2 = 2;
}
위 예제는 byte형 변수 b1에 1 값을 b2에 2 값을 부여하고 있습니다. 이때 각 변수의 비트는 다음과 같을 것입니다.
| b1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| b2 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
이 상태에서 비트 연산자를 적용하게 되면
static void Main(string[] args)
{
byte b1 = 1;
byte b2 = 2;
int r = b1 & b2;
WriteLine(r);
}
결과는 아래와 같이 바뀌게 됩니다.
| b1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| b2 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
| r | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
예제에서 사용된 &는 논리곱 연산자이므로 두 비트가 모두 1이 되어야만 1이 됩니다. 하지만 b1, b2 두 변수의 비트를 순서대로 나열해 보면 동시에 1이 되는 비트가 없으므로 0으로만 비트가 채워지게 되고 결국 값은 0이 됩니다.
● 할당 연산자
변수에 어떠한 값을 할당하는 연산자로서 다음과 같은 연산자를 활용할 수 있습니다.
| 연산자 | 기능 |
| = | 오른쪽 피연산자값을 왼쪽 피연산자에 할당합니다. |
| += | 피연산자에 + 연산을 수행한 후 왼쪽 피연산자에 결과값을 할당합니다. |
| -= | 피연산자에 - 연산을 수행한 후 왼쪽 피연산자에 결과값을 할당합니다. |
| *= | 피연산자에 * 연산을 수행한 후 왼쪽 피연산자에 결과값을 할당합니다. |
| /= | 피연산자에 / 연산을 수행한 후 왼쪽 피연산자에 결과값을 할당합니다. |
| %= | 피연산자의 나머지를 왼쪽 피연산자에 할당합니다. |
| &= | 피연산자에 논리곱 연산을 수행한 후 왼쪽 피연산자에 결과값을 할당합니다. |
| != | 피연산자에 논리합 연산을 수행한 후 왼쪽 피연산자에 결과값을 할당합니다. |
| ^= | 피연산자에 베타적 논리합 연산을 수행한 후 왼쪽 피연산자에 결과값을 할당합니다. |
| <<= | 피연산자에 왼쪽 시프트 연산을 수행한 후 왼쪽 피연산자에 결과값을 할당합니다. |
| >>= | 피연산자에 오른쪽 시프트 연산을 수행한 후 왼쪽 피연산자에 결과값을 할당합니다. |
static void Main(string[] args)
{
int i = 10;
int j = 20;
i += j; //i와 j피연산자의 값을 모두 합한 결과를 다시 i변수에 할당
WriteLine(i); //30출력
}
● null 병합 연산자
물음표 2개를 사용하는 연산자로, 피연산자의 null(아무 값도 가지지 않은 상태) 상태를 확인하고 null이 아니면 왼쪽 피연산자 값을, null이면 오른쪽 피연산자 값을 반환합니다.
static void Main(string[] args)
{
int? i = null;
WriteLine(i ?? 0); //i가 null이므로 0출력
i = 10;
WriteLine(i ?? 0); //i가 null이 아니므로 10출력
}
8. 연산자 우선순위
연산자를 여러 개 겹쳐서 사용하는 경우 연산자의 우선순위에 따라 식이 계산됩니다.
| 순위 | 연산자 |
| 1 | 후위 ++, 후위 --, ?., ?[] |
| 2 | 전위 ++, 전위 -- |
| 3 | *, /, % |
| 4 | +, - |
| 5 | <<, >> |
| 6 | <, >, <=, >=, is, as |
| 7 | ==, != |
| 8 | & |
| 9 | ^ |
| 10 | | |
| 11 | && |
| 12 | || |
| 13 | ?? |
| 14 | ?: |
| 15 | =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |= |
우선순위가 같은 경우는 왼쪽에 있는 연산자가 우선이 되며 또한 각 연산자마다 우선순위가 정해져 있다 하더라도 괄호(())를 사용해 묶어주면 괄호 안의 연산자가 더 높은 우선순위를 갖게 됩니다.
static void Main(string[] args)
{
int r = 2 * 2 + 4;
WriteLine(r); //* 연산자가 우선이므로 결과는 8
r = 2 * (2 + 4);
WriteLine(r); //괄호가 우선순위가 높으므로 결과는 12
}
'.NET > C#' 카테고리의 다른 글
| [C#] 메서드 (0) | 2021.09.27 |
|---|---|
| [C#] 제어문 (0) | 2021.09.24 |
| [C#] 데이터 (2) | 2021.09.23 |
| [C#] 시작하기 (0) | 2021.01.13 |
| [C#] MySQL(MariaDB) EntityFramework 사용하기 (0) | 2020.06.04 |