[이것이 C#이다] 4. 연산자

ssu_hyun·2022년 4월 8일
0

C#

목록 보기
8/22

Key point

  • 연산자
  • 연산자의 종류, 사용 방법
  • 연산자 사이 우선순위

4.1 C# 주요 연산자

  • 연산자는 각각 특정 형식에 대해서만 사용이 가능하다.


4.2 산술 연산자

  • 수치 형식의 데이터(정수 형식, 부동 소수점 형식, decimal 형식)를 다루는 연산자
  • 이항 연산자(Binary operator) : 두 개의 피연산자 필요
    [왼쪽 피연산자] [연산자] [오른쪽 피연산자]

// ArithmaticOperators //

using System;

namespace ArithmaticOperators
{
    class MainApp
    {
        static void Main(string[] args)
        {
            int a = 111 + 222;
            Console.WriteLine($"a : {a}");

            int b = a - 100;
            Console.WriteLine($"b : {b}");

            int c = b * 10;
            Console.WriteLine($"c : {c}");

            double d = c / 6.3;
            // 피연산자 중 한 쪽이 부동 소수형이면 부동 소수형 버전의 연산자가 사용되며, 나머지 피연산자도 부동 소수형으로 형식 변환됨
            Console.WriteLine($"d : {d}");

            Console.WriteLine($"22 / 7 = {22 / 7}({22 % 7})");
        }
    }
}


4.3 증가/감소 연산자

  • 할당 연산자의 도움 없이도 해당 변수의 값을 직접 바꿈
  • 변수의 앞에 사용하는지, 뒤에 사용하는지에 따라 연산 방식이 달라짐
    • 변수 앞 사용 : 변수의 값을 변경한 후 해당 문장 실행
    • 변수 뒤 사용 : 해당 문장의 실행이 끝난 후에 변수의 값 변경
    int a = 10;
     Console.WriteLine(a++); // 10 출력. 출력 후 11로 증가
     Console.WriteLine(++a); // 12 출력
     int a = 10;
     Console.WriteLine(a--); // 10 출력. 출력 후 9로 감소
     Console.WriteLine(--a); // 8 출력
// IncDecOperator //

using System;

namespace IncDecOperator
{
    class MainApp
    {
        static void Main(string[] args)
        {
            int a = 10;
            Console.WriteLine(a++);
            Console.WriteLine(++a);

            Console.WriteLine(a--);
            Console.WriteLine(--a);
        }
    }
}


4.4 문자열 결합 연산자

// StringConcatenate //

using System;

namespace StringConcatenate
{
    class MainApp
    {
        static void Main(string[] args)
        {
            string result = "123" + "456";
            Console.WriteLine(result);

            result = "Hello" + " " + "World!";

            Console.WriteLine(result);
        }
    }
}


4.5 관계 연산자 (Relational Operator)

  • 두 피연산자 사이의 관계를 평가하는 연산자
  • 관계 연산자의 연산 결과는 논리 형식, 즉 bool(참 또는 거짓)
// RelationalOperator //

using System;

namespace RelationalOperator
{
    class MainApp
    {
        static void Main(string[] args)
        {
            Console.WriteLine($"3 > 4  : {3 > 4}");
            Console.WriteLine($"3 >= 4 : {3 >= 4}");
            Console.WriteLine($"3 < 4  : {3 < 4}");
            Console.WriteLine($"3 <= 4 : {3 <= 4}");
            Console.WriteLine($"3 == 4 : {3 == 4}");
            Console.WriteLine($"3 != 4 : {3 != 4}");
        }
    }
}


4.6 논리 연산자(Logical Operation)

  • 참과 거짓으로 이루어지는 진리값이 피연산자인 연산

  • 논리 연산자 종류

    • 논리곱 연산자(&& : AND)

      • 피연산자로 오는 두 개의 진릿값이 모두 참이어야 결과가 참(True)이 되고,
        그 외에는 모두 거짓(False)이 된다.
    • 논리합 연산자(|| : OR)

      • 두 개의 진릿값 중에 하나라도 참이면 연산 결과 참
    • 부정 연산자(! : NOT)

      • 피연산자의 진릿값을 반대로 뒤집음
// LogicalOperator //

using System;

namespace LogicalOperator
{
    class MainApp
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Testing && ... ");
            Console.WriteLine($"1 > 0 && 4 < 5 : {1 > 0 && 4 < 5}");
            Console.WriteLine($"1 > 0 && 4 > 5 : {1 > 0 && 4 > 5}");
            Console.WriteLine($"1 == 0 && 4 > 5 : {1 == 0 && 4 > 5}");
            Console.WriteLine($"1 == 0 && 4 < 5 : {1 == 0 && 4 < 5}");

            Console.WriteLine("\nTesting || ... ");
            Console.WriteLine($"1 > 0 || 4 < 5 : {1 > 0 || 4 < 5}");
            Console.WriteLine($"1 > 0 || 4 > 5 : {1 > 0 || 4 > 5}");
            Console.WriteLine($"1 == 0 || 4 > 5 : {1 == 0 || 4 > 5}");
            Console.WriteLine($"1 == 0 || 4 < 5 : {1 == 0 || 4 < 5}");

            Console.WriteLine("\nTesting ! ...");
            Console.WriteLine($"!True : {!true}");
            Console.WriteLine($"!False: {!false}");
        }
    }
}


4.7 조건 연산자(Conditional Operator)

  • [조건식] ? [참일 때의 값] : [거짓일 때의 값]
    • 피연산자 3개
    • 조건식 : 논리값 (해당 결과에 따라 매개변수 선택이 달라진다.)
    • 참일 때의 값, 거짓일 때의 값 : 둘의 형식만 같으면 됨
    int a = 30;
     string result = a == 30 ? "삼십" : "삼십아님";  // reault는 "삼십"
     // == 30 → 조건식
     // "삼십" → 참일 때의 값
     // "삼십아님" → 거짓일 때의 값
// ConditionalOperator //

using System;

namespace ConditionalOperator
{
    class MainApp
    {
        static void Main(string[] args)
        {
            string result = (10 % 2) == 0 ? "짝수" : "홀수";

            Console.WriteLine(result);
        }
    }
}


4.8 null 조건부 연산자

  • C# 6.0에서 도입
  • ?. : 객체의 멤버에 접근하기 전에 해당 객체가 null인지 검사하여 그 결과가 참이면 그 결과로 null 반환하고, 그렇지 않은 경우에는 . 뒤에 지정된 멤버 반환
  • ?[] : 객체의 멤버 접근이 아닌 배열과 같은 컬렉션 객체의 첨자를 이용한 참조에 사용된다.
// NullConditionalOperator //

using System.Collections;
using static System.Console;

namespace NullConditionalOperator
{
    class MainApp
    {
        static void Main(string[] args)
        {
            ArrayList a = null;
            a?.Add("야구"); // a?.가 null을 반환하므로 Add() 메소드는 호출되지 않음
            a?.Add("축구");
            // a?.가 null을 반환하므로 "Count :"외에는 아무것도 출력하지 않는다.
            WriteLine($"Count : {a?.Count}");
            WriteLine($"{a?[0]}");
            WriteLine($"{a?[1]}");

            a = new ArrayList(); // a는 이제 더 이상 null이 아니다.
            a?.Add("야구");  // 배열 a에 "야구" 추가
            a?.Add("축구");  // 배열 a에 "축구" 추가
            WriteLine($"Count : {a?.Count}");  // 배열 길이 count
            WriteLine($"{a?[0]}");  // 배열 a의 0번째 요소
            WriteLine($"{a?[1]}");  // 배열 a의 1번째 요소
        }
    }
}


4.9 비트 연산자

비트 수준에서 데이터를 가공해야 하는 경우를 위한 연산자

4.9.1 시프트 연산자(Shift Operator)

  • 비트를 왼쪽이나 오른쪽으로 이동시키는 연산자
    • 왼쪽 시프트 연산
      • 원본데이터를 a, 옮길 비트의 수를 b라 할 때 a×2ba × 2^b의 결과 도출
    • 오른쪽 시프트 연산
      • 원본데이터를 a, 옮길 비트의 수를 b라 할 때 a÷2ba ÷ 2^b의 결과 도출
    • 음수에 대한 오른쪽 시프트 연산
      • 이동시킨 후 만들어진 빈 자리에 0이 아닌 1을 채워 넣는다.
  • 형식 : [원본 데이터] [시프트 연산자] [옮길 비트의 수]
  • 사용 목적
    • 고속의 곱셈과 나눗셈 구현
    • &, |연산자와 함께 byte처럼 작은 단위로 쪼개진 데이터를 다시 하나의 int나 long 형식으로 재조립
// ShiftOperator //

using System;

namespace ShiftOperator
{
    class MainApp
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Testing <<...");

            int a = 1;
            /* 1바이트(8비트)로 나타낼 수 있는 수는 256가지이므로
            8자리의 16진수면 int 형식이 표현하는 모든 수를 나타낼 수 있다.*/
            // D5 : 10진수 5자리 | X8 : 16진수 8자리
            Console.WriteLine("a      : {0:D5} (0x{0:X8})", a); // a = 1
            Console.WriteLine("a << 1 : {0:D5} (0x{0:X8})", a << 1); // 1×2^1
            Console.WriteLine("a << 2 : {0:D5} (0x{0:X8})", a << 2); // 1×2^2
            Console.WriteLine("a << 5 : {0:D5} (0x{0:X8})", a << 5); // 1×2^5

            Console.WriteLine("\nTesting >>...");

            int b = 255;
            Console.WriteLine("b      : {0:D5} (0x{0:X8})", b); // b = 255
            Console.WriteLine("b >> 1 : {0:D5} (0x{0:X8})", b >> 1); // 255÷2^1
            Console.WriteLine("b >> 2 : {0:D5} (0x{0:X8})", b >> 2); // 255÷2^2
            Console.WriteLine("b >> 5 : {0:D5} (0x{0:X8})", b >> 5); // 255÷2^5

            Console.WriteLine("\nTesting >> 음수...");

            int c = -255; // 음수
            Console.WriteLine("c      : {0:D5} (0x{0:X8})", c); // c = -255
            Console.WriteLine("c >> 1 : {0:D5} (0x{0:X8})", c >> 1);
            Console.WriteLine("c >> 2 : {0:D5} (0x{0:X8})", c >> 2);
            Console.WriteLine("c >> 5 : {0:D5} (0x{0:X8})", c >> 5);
        }
    }
}


4.9.2 비트 논리 연산자(Bitwise Logical Operator)

데이터의 각 비트에 대해 수행하는 논리 연산

  • bool 형식 외에 정수 계열 형식의 피연산자에 대해서도 사용할 수 있다.

  • 정수 형식 논리 연산

    • 데이터는 0과 1로 이루어져있다. 비트 논리 연산은 이 비트 덩어리를 이루고 있는 각 비트에 대해 1은 참, 0은 거짓으로 해서 논리 연산을 하는 것이다.
      • int : 4바이트(32비트), long : 8바이트(64비트)
    • 논리곱 연산자(&) : 두 비트 모두 1(참) → 1(참)
      int result = 9 & 10;  // result는 8

    • 논리합 연산자(|) : 둘 중 하나라도 1(참) → 1(참)
      int result = 9 | 10;  // result는 11

    • 배타적 논리합 연산자(^) : 두 진릿값이 서로 달라야 → 1(참)
      int result = 9 ^ 10;  // result는 3

    • 보수 연산자(~) : 단항 연산자로 비트를 0에서 1로, 1에서 0으로 뒤집는 기능
      int a = 255;
      int result = ~a; // result는 -256


// BitwiseOperator //

using System;

namespace BitwiseOperator
{
    class MainApp
    {
        static void Main(string[] args)
        {
            int a = 9;
            int b = 10;

            Console.WriteLine($"{a} & {b} : {a & b}");
            Console.WriteLine($"{a} | {b} : {a | b}");
            Console.WriteLine($"{a} ^ {b} : {a ^ b}");

            int c = 255;
            Console.WriteLine("~{0}(0x{0:X8}) : {1}(0x{1:X8})", c, ~c);
        }
    }
}


4.10 할당 연산자 (Assignment Operator)

변수 또는 상수에 피연산자 데이터를 할당하는 기능

// AssignmentOperator //

using System;
using static System.Console;

namespace AssignmentOperator
{
    class MainApp
    {
        static void Main(string[] args)
        {
            int a;
            WriteLine($"a = 100 : {a = 100}");
            WriteLine($"a += 90 : {a += 90}");
            WriteLine($"a -= 80 : {a -= 80}");
            WriteLine($"a *= 70 : {a *= 70}");
            WriteLine($"a /= 60 : {a /= 60}");
            WriteLine($"a %= 50 : {a %= 50}");
            WriteLine($"a &= 40 : {a &= 40}");
            WriteLine($"a |= 30 : {a |= 30}");
            WriteLine($"a ^= 20 : {a ^= 20}");
            WriteLine($"a <<= 10: {a <<= 10}");
            WriteLine($"a >>= 1 : {a >>= 1}");
    }
}


4.11 null 병합 연산자

  • [왼쪽 피연산자] ?? [오른쪽 피연산자]

  • 프로그램에서 종종 필요한 변수/객체의 null 검사를 간결하게 만들어주는 역할

  • 두 개의 피연산자를 받아들이고 왼쪽 피연산자가 null인지 평가

    • null이 아니면 왼쪽 피연산자 반환
    • null이면 오른쪽 피연산자 반환
    int? a = null;
     Console.WriteLine($"{a ?? 0}"); // a는 null이므로 0 출력
    
     a = 99;
     Console.WriteLine($"{a ?? 0}"); // a는 null이 아니므로 99 출력
// NullCoalescing //

using System;

namespace NullCoalescing
{
    class MainApp
    {
        static void Main(string[] args)
        {
            int? num = null;
            Console.WriteLine($"{num ?? 0}"); // num은 null이므로 0 출력

            num = 99;
            Console.WriteLine($"{num ?? 0}"); // num은 null이 아니므로 99 출력

            string str = null;
            Console.WriteLine($"{str ?? "Default"}"); // num은 null이므로 Default 출력

            str = "Specific";
            Console.WriteLine($"{str ?? "Default"}"); // num은 null이 아니므로 Specific 출력
        }
    }
}


4.12 연산자 우선순위

C# 연산자들 사이에는 연산의 우선순위가 존재한다.


연습문제

  1. i++과 ++i의 차이점은 무엇인가요?
    → 둘은 연산 방식이 다르다. i++은 코드가 실행될 때 i값 출력 후 해당 변수에 1을 더하고 ++i는 해당 변수에 1을 더하고 i값을 출력한다.

  2. 다음 보기 중 그 결과가 다른 것을 찾으세요(변수 i를 초기화해서 각 보기를 실행해보면 그 결과가 나옵니다. 고민을 좀 해본 후에 답을 확인해보세요.) → ②
    ① i = i + 1; // 2
    ② i++; // 1
    ③ ++i; // 2
    ④ i+=1; // 2

  3. 다음 코드에서 a와 b는 각각 얼마일까요? → a = 4, b = 1

int a = 8 >> 1; // 8÷2^1 = 4
int b = a >> 2; // 4÷2^2 = 1
// 1000(8)
// 0100(4)
// 0001(1)
  1. 다음 코드에서 a는 얼마일까요? → 255
int a = 0xF0 | 0x0F;
using System;

namespace practice
{
    class MainApp
    {
        static void Main(string[] args)
        {   Console.WriteLine($"0xF0 : {0xF0}");
            Console.WriteLine($"0x0F : {0x0F}");
            Console.WriteLine($"0xF0 | 0x0F : {0xF0 | 0x0F}");
        }
    }
}

  1. 다음 코드에서 b는 어떤 값을 가질까요? → ABC
int a = 10;
string b = a == 0 ? "가나다" : "ABC";
// a는 10이 아니므로 b는 ABC의 값을 가진다.

0개의 댓글