컴퓨터는 문자와 숫자를 구분하지 못한다. 그렇다면 문자로 등록되어 있는 문자열을 숫자로 바꿀 수 있는가? 답은 그렇다 이다. 

 

string a = "12";

라는 값이 있다고 생각해보자. 이는 분명히 문자열입니다. 12라는 문자열이죠. 이를 다른 숫자와 더하려고 한다면 문제가 생깁니다.

 

using System;

namespace MyFirstApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string a = "12";
            string b = "13";

            Console.WriteLine(a+b);
            
        }
    }
}

 

  위의 코드를 입력하고 실행해보시면, 출력 결과로 1213를 받을 수 있습니다. 문자열로 선언된 두 개의 문자열이기 때문에 우리가 원하는 결과인 12+13 = 25의 결과를 받지 못한 것 입니다. 그렇다면 어떻게 12와 13을 숫자로 바꿔야 할까요?

 

  여기에 대한 답은 Parse를 쓰거나 ToInt32 메소드를 사용하는 것 입니다. 

 

using System;

namespace MyFirstApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string a = "12";
            string b = "13";

            Console.WriteLine(a+b);

            int c = int.Parse(a);
            int d = int.Parse(b);

            Console.WriteLine(c + d);

            int e = Convert.ToInt32(a);
            int f = Convert.ToInt32(b);

            Console.WriteLine(e + f);
            
        }
    }
}

실행해보면 우리가 원하는 값인 25를 얻을 수 있습니다. 문자열을 숫자로 바꿀 수 있는 것처럼 숫자를 문자열로도 바꿀 수 있습니다. 

 

만약 a 문자열 변수에 12가 아닌 "안녕?" 을 넣으면 어떻게 될까요? 

답은 실행은 되지만 오류가 납니다.

 

 

이러한 형태로 말이죠!
(물론! 입력타입을 검사해서 적합한 타입이면 정수형으로 바꾸어주는 메소드가 존재합니다.)

 

추가로 현재 변수가 가지는 데이터형을 알아내는 메소드도 있습니다.

 

GetType()

GetType() 메소드를 활용하면 현재의 데이터 형이 무엇인지 바로 알 수 있습니다. 

 

using System;

namespace MyFirstApp
{
    class Program
    {
        static void Main(string[] args)
        {
            int a = 10;
            float b = 10.32f;
            string c = "abc";

            Console.WriteLine("a의 데이터 형은 : {0}", a.GetType());
            Console.WriteLine("b의 데이터 형은 : {0}", b.GetType());
            Console.WriteLine("c의 데이터 형은 : {0}", c.GetType());

        }
    }
}

이렇게 메소드를 활용하면 각각의 형태를 하나씩 출력해보면서 확인해볼 수 있습니다. 

이 외에도 문자열을 다룰 수 있는 여러 메소드가 존재합니다. IndexOf(), LastIndexOf(), Contains(), ToLower(), ToUpper() 등이 있지만 이러한 부분도 뒤에 가서 다루도록 하겠습니다. 

# 추가 실습으로 우리가 배운 데이터 형을 선언해보고 각각의 형을 확인해보시길 바랍니다. 


Const는 상수

변수를 선언할 때, const를 붙여서 선언하게 되면, 한번 선언한 뒤에 변경이 안되는 상수가 됩니다.

const double pi = 3.14;

우리가 pi라는 형태는 3.14를 많이 사용합니다. 이러한 값을 사용할 때, 단순히 값으로만 입력하면 무엇을 의도했는지 잘 모르겠죠? 그래서 프로그램의 가독성을 위해서 그리고 실수로라도 값을 바꿀 것에 대비해서 const 상수형을 사용하는 것입니다. 여기에 추가로 전체 파일에 대한 수정을 해야 한다고 한다면, 위의 상수 하나만 교체해주면, 프로그램 내부에 있는 모든 상수값이 교체가 됩니다! 

 

실제로 상수 값을 변경하려고 한다면 컴파일에서 컴파일 오류가 납니다. 컴파일러가 상수를 변경할 수 있는 실수를 대신 막아주는 것이죠!

 


Enum 열거형

열거형은 말 그대로 값들을 나열해주는 역할을 합니다. 상수가 많아지거나 선택지가 생기게 될 수도 있습니다. 실제 상수를 너무 많이 사용하게 되면 실제로 실수하는 경우가 생깁니다. 이러한 실수는 컴파일러가 오류를 발생시켜 막아주지도 못합니다. 그렇기에 열거형을 통해 자동으로 값을 배정받도록 하는 것이지요.

 

enum 변수명 {상수1, 상수2, 상수3, ...};

의 형태로 선언합니다. 상수1은 0이라는 숫자를 입력받으며, 상수2는 1의 숫자를 받습니다. 하나씩 증가하면서 각각의 수를 매칭된다고 생각하면 됩니다.

 

어떻게 출력되는가에 대한 예제를 살펴보로독 하겠습니다.

 

using System;

namespace MyFirstApp
{
    class Program
    {
        enum RequestResult { DONE, FAILED, REJECT, APPROVAL };  // 상수는 일반적으로 대문자로 선언합니다.

        static void Main(string[] args)
        {
            Console.WriteLine((int)RequestResult.DONE);
            Console.WriteLine((int)RequestResult.FAILED);
            Console.WriteLine((int)RequestResult.REJECT);
            Console.WriteLine((int)RequestResult.APPROVAL);

        }
    }

 

위의 코드를 실행시켜보면 0, 1, 2, 3의 값이 출력으로 나옵니다. 

 

그러면 여기서 (int)를 빼고 출력해보면 어떻게 될까요?

using System;

namespace MyFirstApp
{
    class Program
    {
        enum RequestResult { DONE, FAILED, REJECT, APPROVAL };  // 상수는 일반적으로 대문자로 선언합니다.

        static void Main(string[] args)
        {
            Console.WriteLine(RequestResult.DONE);
            Console.WriteLine(RequestResult.FAILED);
            Console.WriteLine(RequestResult.REJECT);
            Console.WriteLine(RequestResult.APPROVAL);

        }
    }
}

결과는 DONE, FAILED, REJECT, APPROVAL의 형태로 출력됩니다! 

 

그런데 항상 값이 0부터 시작해서 1씩 증가해야 하는 값이어야 하는가 하면 그렇지 않습니다. 원하는 값으로 배정할 수 있습니다. 

 

using System;

namespace MyFirstApp
{
    class Program
    {
        enum RequestResult { DONE = 100, FAILED = 200, REJECT = 300, APPROVAL = 400 };  // 상수는 일반적으로 대문자로 선언합니다.

        static void Main(string[] args)
        {
            Console.WriteLine((int)RequestResult.DONE);
            Console.WriteLine((int)RequestResult.FAILED);
            Console.WriteLine((int)RequestResult.REJECT);
            Console.WriteLine((int)RequestResult.APPROVAL);

        }
    }
}

이러한 형태로 값을 따로따로 배정하면서 사용할 수도 있습니다. 

 

using System;

namespace MyFirstApp
{
    class Program
    {
        enum RequestResult { DONE = 100, FAILED = 200, REJECT = 300, APPROVAL = 400 };  // 상수는 일반적으로 대문자로 선언합니다.

        static void Main(string[] args)
        {
            RequestResult myResult = RequestResult.DONE;

            Console.WriteLine(myResult == RequestResult.DONE);
            Console.WriteLine(myResult == RequestResult.FAILED);
            Console.WriteLine(myResult == RequestResult.REJECT);
            Console.WriteLine(myResult == RequestResult.APPROVAL);

        }
    }
}

실제 사용은 이러한 형태로 사용됩니다. 우리가 원하는 결과 값을 저장해두고 그러한 값이 온다면 실행시켜주는 형태로 진행하는 것이죠. 여기서 사용된 == 은 같은 값인지 아닌지를 확인시켜주는 비교 연산자입니다. 결과가 같으면 true를 아니면 false를 반환합니다. 

앞서 데이터 형과 변수 (상)편에 이은 포스팅입니다. 이전 글에 대한 정보는

[C# 입문] 데이터 형과 변수 (상) 에 있습니다.

 


문자를 다루는 방법에는 문자 자체를 다루는 문자 형식과 문자로 이루어진 문자열 형식으로 문자들을 다룰 수 있습니다. char과 string입니다. 

char

문자 형 char는 1개의 문자를 다루는 데이터 형입니다. 우리가 Hello, World를 입력한다고 생각합시다. 그러면 char형으로는 하나하나 입력해주어야 하는 것이죠.

 

using System;

namespace MyFirstApp
{
    class Program
    {
        static void Main(string[] args)
        {
            char a = 'H';
            char b = 'e';
            char c = 'l';
            char d = 'l';
            char e = 'o';
            char f = ',';
            char g = ' ';
            char h = 'W';
            char i = 'o';
            char j = 'r';
            char k = 'l';
            char l = 'd';

            Console.Write(a);
            Console.Write(b);
            Console.Write(c);
            Console.Write(d);
            Console.Write(e);
            Console.Write(f);
            Console.Write(g);
            Console.Write(h);
            Console.Write(i);
            Console.Write(j);
            Console.Write(k);
            Console.WriteLine(l);

        }
    }
}

 이렇게 하나의 문자를 담을 수 있는 것을 char형이라 합니다. 이러한 char형을 모아두면 string이라고 하는 문자열이 됩니다.

 

using System;

namespace MyFirstApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string a = "Hello, World!";

            Console.WriteLine(a);

        }
    }
}

 

위의 문자로 이루어진 복잡한 형태가 문자열로 깔끔한 형태로 바꾸어주었습니다. 이러한 문자열 string은 정해진 데이터 범위가 없습니다. 데이터가 저장될 수 있는 양이 그때마다 다르기 때문이죠. 

 

그렇다면 여기서 또 생각해볼 수 있는 형태가 있습니다. 만약 문자열과 문자열을 더하게 되면 어떻게 될까요?

 

using System;

namespace MyFirstApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string a = "Hello, World!";
            string b = " 안녕 세상!";
            string c;

            c = a + b;

            Console.WriteLine(c);

        }
    }
}

출력 결과를 확인하면

 

두 개의 문자열이 더해져서 나오는 것을 확인할 수 있습니다. 이렇듯 문자열은 다양한 상태로 사용될 수 있습니다. 그렇다면 여기서 문자의 갯수를 세고 싶다면 어떻게 해야할까요? 직접 하나하나 세야 할까요? 그렇지 않습니다. 우리에게는 강력한 메소드가 있으니까요!

 

using System;

namespace MyFirstApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string a = "Hello, World!";
            string b = " 안녕 세상!";
            string c;

            c = a + b;

            Console.WriteLine(a.Length);
            Console.WriteLine(b.Length);
            Console.WriteLine(c.Length);

        }
    }
}

실제 실행을 시켜보면 13, 7, 20이 나옵니다.

실제로 하나씩 세어보도록 하겠습니다.

H e l l o ,   W o r
l d !              

총 13개의 문자가 나옴을 확인할 수 있습니다. 중간에 있는 공백을 포함해서 말이죠.

 

    !      

여기도 공백을 포함해서 7개임을 확인할 수 있습니다. 

c는 a와 b를 합친 것이므로 총 20개의 문자를 세어준 것이죠. 실제 Length의 역할을 string에 들어있는 char 유니코드 문자수가 아니라 인스턴스의 개체 수를 반환해서 수를 세어줍니다. 일반적으로 string에는 마지막에 널문자가 들어갑니다.

H e l l o null문자        

이러한 형태로 마지막 부분에 널문자를 넣음으로써 컴퓨터에게 문자열의 마지막임을 알립니다. 하지만 Length는 마지막 Null 문자를 제외하고 문자의 갯수를 공백을 포함해서 세어줍니다. 아주 편리한 기능이죠?

 


문자열에서는 사용하고 싶은 특수한 문자가 있을 수 있습니다. 예를 들어, ", \, /이러한 형태의 문자는 이대로 사용할 수 없습니다. 그래서 이러한 특수한 문자를 사용할 수 있게 하기 위해서 이스케이프 문자를 만들어두었습니다. 이스케이프 문자를 활용하면 언제든 특수한 문자를 사용할 수 있습니다. 

 

using System;

namespace MyFirstApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string a = "Hello, \t this is tab \tand space";
            string b = "\" 큰 따움표를 사용하기 위해서는 \\를 입력해야 합니다.";

            //우리는 \를 이스케이프 문자라 합니다.

            Console.WriteLine(a);


        }
    }
}

 이스케이프 문자는 엔터 위에 있는 ' \ ' 표시가 이스케이프 문자입니다. 사용하는 곳에 따라 다르게 보이기 때문에 키보드 자판 상 돈 표시를 하고 있습니다.

 

이스케이프 형태 문자 이름 유니코드 인코딩
\' 작은 따옴표 0x0027
\" 큰 따옴표 0x0022
\\ 백 슬래시 0x005C
\0 NULL 0x0000
\a 경고 0x0007
\b 백스페이스 0x0008
\f 폼 피드 0x000C
\n 줄 바꿈 0x000A
\r 캐리지 리턴 0x000D
\t 탭 (시스템 설정에 따라 다름) 0x0009
\v 세로 탭 0x000B

등이 있습니다. 

 


Bool

  참과 거짓으로 이루어진 논리형 입니다. 단순히 true와 false 두가지 밖에 없습니다. 간략한 형태지만 프로그래머들에게는 강력한 도구가 됩니다. bool형이 없는 프로그래밍 언어에서는 0과 1로써 참과 거짓을 표현했는데, 이는 코드를 읽을 때 가독성이 떨어지게 됩니다. 하루에도 수십 줄의 코드를 읽는 프로그래머 입장에서는 굉장히 힘든일이죠. 그래서 bool형은 프로그래머가 코드를 더 잘 읽을 수 있도록 만들어주는 큰 역할을 했습니다.

 

  간략하게 bool형에 대해 살펴보겠습니다.

 

using System;

namespace MyFirstApp
{
    class Program
    {
        static void Main(string[] args)
        {
            bool a = true;
            bool b = false;

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

이 코드를 실행하면 treu와 false가 출력됩니다. 

 


이렇게 기본적인 데이터형에 대해서는 마무리가 되었습니다. 아직 안한 object형도 있지만, 나중에 상속에 대한 이야기를 배운 뒤에 object를 더 자세히 다루도록 하겠습니다. 감사합니다!

 

Hello, World! 코드 분석해보기! 지난 강의에서 2개의 프로그래밍 문제를 드렸습니다. 이 문제에 대한 답부터 살펴보도록 하겠습니다. 

 

첫 번째 문제에 대한 해답은

using System;

namespace MyFirstApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("안녕하세요. 저는 OO입니다.");
            Console.WriteLine("앞으로 우리의 프로그램을 재밋게 해보도록 하겠습니다.");
            Console.WriteLine("다음에 뵙겠습니다!");
        }
    }
}

 두번째 문제에 대한 해답은

using System;

namespace MyFirstApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("이 줄은 첫번째 줄입니다.");
            Console.WriteLine("");
            Console.WriteLine("이 줄은 세번째 줄입니다.");
            Console.WriteLine("");
            Console.WriteLine("이 줄은 다섯번째 줄 입니다.");
        }
    }
}

 

로 볼 수 있겠습니다. 이 코드와 다르게 쓰셨다고 해도 틀린 것은 아닙니다. 다양한 방법이 있으며 여기에는 이러한 방법이 있다고 볼 수 있습니다. 출력된 결과가 같으면 정답이라 생각하시면 됩니다. 

 


 

 

  이번 포스팅에서는 C#에서 사용되는 데이터 종류에 대해 살펴보도록 할 예정입니다. C#에서 정의된 상태를 이야기하는 것이다 보니 글 자체가 지루해질 우려가 있지만, 반드시 필요한 부분이기도 하니 한 번쯤 쭈욱 읽어보신 다음에 하나하나 직접 쳐보시면서 익혀보는 시간을 갖도록 하시면 됩니다. 

 

  정말 단순한 내용이지만, 단순한 내용이기에 오히려 어려워질 수 있는 단원입니다. 꼭 한번은 끝까지 읽어보시기 바랍니다. 

 


  앞서 이야기햇듯이 컴퓨터는 데이터의 종류를 딱딱 알아맞히지 못합니다. (물론 어느 정도는 컴퓨터 스스로가 판단할 수 있도록 설계되어 있기는 합니다.) 예를 들어, 12와 "12"는 다른 형태로 받아들입니다. 그냥 12는 정수로 받아들여지며, "12"는 문자열로 쓰입니다. 인간은 이를 한 번에 알아들을 수 있도록 12라는 숫자로 자동으로 변환해서 생각합니다. 하지만 컴퓨터는 아니죠.

 

  그래서 필요한 것이 데이터형이 필요합니다. 컴퓨터가 어느정도 추측할 수도 있지만, 이러한 추측은 프로그래머 입장에서 설계의 혼란이 오기 마련입니다. 예를 들어, 숫자 12로 저장하려고 했는데, 컴퓨터의 추측으로 12라는 문자로 입력되면 이후에 오류가 나기 마련입니다. 

 

  이러한 수많은 데이터에 대한 통일을 하기 위해서는 반드시 명시적인 데이터형이 정의되어 있어야 합니다. 

 

  C#의 데이터 형식은 두 가지를 기본 근간으로 이루고 있습니다. 기본 데이터 형식복합 데이터 형식으로 크게 나눌 수 있습니다. 그리고 이러한 데이터 형식은 값 형식참조 형식으로 나누어 집니다.당장에는 기본 데이터 형식에 대해서 살펴보도록 하고 나중에 복합 데이터 형식에 대해 살펴보고자 합니다.

 


기본 데이터 형식

데이터 형식 .NET 형식(Type) 비트 범위
byte System.Byte 부호 없는 정수 8 0 ~ 255
sbyte System.SByte 부호 있는 정수 8 -128 ~ 127
short System.Int16 부호 있는 정수 16 -32,768 ~ 32,767
ushort System.UInt16 부호 없는 정수 16 0 ~ 65,535
int System.Int32 부호 있는 정수 32 -2,147,483,648 ~ 2,147,4283,647
uint System.UInt32 부호 없는 정수 32 0 ~ 4,294,967,295
char System.Char 유니코드 문자 16 -
string System.String 문자 시퀀스 - -
bool System.Boolean 논리 형식 8 true, false
object System.Ojbect 모든 형의 기본 형식 - -
long System.Int64 부호 있는 정수 64 -922,337,203,685,477,508 ~ 922,337,203,685,477,507
ulong System.UInt64 부호 없는 정수 64 0 ~ 18,446,744,073,709,551,615
float System.Single 단정밀도 부동 소수점 형식 32 -3.402823e38 ~ 3.402823e38
double System.Double 배정밀도 부동 소수점 형식 64 -1.79769313486232e308 ~ 1.79769313486232e308
decimal System.Decimal 10진수 부동 소수점 숫자 128 -3.402823e38 ~ 3.402823e38

  여기서 1.3e2 의 형태로 쓰인 수는 1.3 × 10의 제곱 형태를 의미합니다. 우리가 고등학교 때, 배운 로그에서와 비슷한 형태를 의미합니다. 수의 과학적 표기 기법에 따라 표시한 수를 의미합니다. 큰 수를 표시할 때는 e는 에러의 e가 아니라 지수의 Exponent의 e입니다. 

 

이러한 수의 범위를 직접 확인할 수 있는데, 그 방법은 int.MaxValue와 int.MinValue를 사용하는 것입니다.

 

using System;

namespace MyFirstApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("byte의 최댓값 : " + byte.MaxValue);
            Console.WriteLine("byte의 최솟값 : " + byte.MinValue);

            Console.WriteLine("sbyte의 최댓값 : " + sbyte.MaxValue);
            Console.WriteLine("sbyte의 최솟값 : " + sbyte.MinValue);

            Console.WriteLine("char의 최댓값 : " + char.MaxValue);
            Console.WriteLine("char의 최솟값 : " + char.MinValue);
            
            Console.WriteLine("float의 최댓값 : " + float.MaxValue);
            Console.WriteLine("float의 최솟값 : " + float.MinValue);

            Console.WriteLine("double의 최댓값 : " + double.MaxValue);
            Console.WriteLine("double의 최솟값 : " + double.MinValue);

        }
    }
}

 알아보고자 하는 데이터형에다가 .MaxValue를 써주면 됩니다. 위에 코드는 몇 개만 살펴보았지만, 위에서 소개한 데이터형을 더 넣어봄으로써 각각의 값을 확인해보시기 바랍니다. 

 

  실제 실행하면

이러한 형태가 나오는데, char의 값은 ?로 나오는 것을 확인할 수 있습니다. 저장된 값에 따라 값이 변하기 때문에 이러한 형태가 됩니다. 지금은 알 수 없는 값이기에 값이 나오지 않고 있습니다. 심지어 문자열을 저장하는 데이터형인 string은 출력해보려고 하면 오류가 나옵니다. 

 

 


값 형식(Primitive Data Type)과 참조 형식 (Reference Type)

  기본 데이터와 복합 데이터 형에는 각각 값 형식과 참조 형식이 존재합니다. 값 형식은 실제 값을 변수를 통해 데이터를 저장하며, 참조 형식은 참조할 위치에 대한 주소를 저장하는 역할을 합니다. 조금 더 자세히 살펴보면 값 형식은 스택에 의해 저장되며, 참조 형식은 힙과 스택에 의해 할당됩니다. 스택에는 참조하고자 하는 주소지가 저장되어 있는 것이지요. (그리고 가비지 컬렉터에 의해서 할당된 값이 해제됩니다.) 이는 나중에 다시 이야기하도록 하겠습니다.  (이 부분에 대해 자세히 이야기하기 위해서는 스택과 힙이 필요한데, 자료구조에 대한 이야기이므로 나중에 자세히 살펴보도록 하겠습니다.) 

 

* 기본 데이터 형식에는 숫자 형식, 논리 형식, 문자열 형식, 오브젝트 형식으로 크게 나누어 집니다. 여기서 문자열 형식과 오브젝트 형식만 참조형식이며 숫자 형식, 논리 형식은 값 형식입니다.

 

* 스택은 책을 쌓아둔 것을 생각하시면 됩니다. 그래서 가장 먼저 들어간 것이 가장 나중에 나오는 선입 후출의 형태를 가집니다. 

(좌) 힙, (우) 스택

* 힙은 이진 트리라 불리는 형태를 가집니다. 가지가 2개 짜리인 나무 구조를 연상시키는 형태를 의미합니다. 이러한 트리 형태는 컴퓨터에서 자주 쓰이는 자료 구조입니다. 나중에 알아보도록 하겠습니다. 


변수

변수는 값을 저장할 수 있는 공간을 의미합니다. 

int a;
char b;
string c;

  이러한 a, b, c를 변수라 부릅니다. 컴퓨터에서 메모리에 '일정한 공간 만큼을 할당하라'라고 명령을 내리는 역할을 합니다. 그리고 위에서 본 것처럼, 각 데이터형에 따라 얼마만큼의 비트를 할당할지 결정하게 됩니다. a라는 변수는 32비트만큼의 메모리를 차지하고 있습니다. 마치 우리가 살고 있는 현실 세계에서 특정한 땅만큼을 배정해주고, a씨네 집이라고 이름 짓는 것과 같습니다. 

 

   실제 주소는 서울시 코딩서로 200번 길 32처럼 있지만, a씨네 집이라고 별칭을 지어주는 것이지요. 메모리에서도 같은 일이 일어납니다. a라는 변수에는 메모리 주소가 저장되며, a라는 별칭을 통해 이 메모리에 접근하자 라고 약속을 해두는 것입니다. C#에서는 메모리에 대해 크게 신경 쓰지 않아도 되도록 가비지 컬렉터가 존재합니다. 이 부분은 다시 나중에 이야기하도록 하겠습니다. 다만 변수를 선언하면 메모리에 올라가며, 메모리에 직접적으로 접근하는 것은 불가능하며, 변수라는 메모리 주소의 별칭을 통해 접근한다 정도로 이해하시면 되겠습니다.

그림으로 그려보자면 이러한 느낌입니다. 

int a = 10; int라는 데이터 형을 가진 a라는 변수에는 10이 저장되어 있다. 그리고 그 주소는 1000이다. int는 32비트이지만 바이트로 표현하면 4바이트이다. 그래서 주소지도 4씩 증가하는 형태로 표현되어 있다! 

 

※ 변수는 메모리에서 특정한 자리를 차지하는 영역에 대한 별칭을 의미한다! 정도가 변수의 의미라 생각할 수 있겠습니다. 

 

초기 프로그래밍 언어에서는 변수를 선언한 뒤에 반드시 초기화가 필요했습니다. 초기화를 하지 않으면 '쓰레기 값'이라 불리는 임의의 아무 값이 들어가기 때문이죠. 이러한 쓰레기 값으로 인해 프로그램이 오류가 생길 가능성이 있었어서 초기에는 초기화가 필수가 되었습니다. C#에는 초기화를 하지 않으면 컴파일 수준에서 오류를 발생시킵니다. 초기화는 일반적으로 정수 값이라면 0을 넣습니다. 

 


리터럴(Literal)

리터럴이라 하면 문자 그대로의 값을 의미합니다. 실제 사전 상의 의미도 "문자 그대로의"라는 의미가 있습니다. 다음의 코드를 살펴보도록 하겠습니다.

int a = 100;

이라는 코드에서 100은 리터럴입니다. 100이라는 의미 그대로를 가지고 있기 때문입니다. 100이라는 숫자가 쓰이기 위해서는 어떤 부분에는 저장이 되어야 할 것입니다. 이러한 형태로 100이라는 문자 그대로의 의미를 가지는 진짜 숫자가 저장된 형태가 리터럴이라 부릅니다. 고등학교 수학에서는 상수라 불리던 것이 리터럴과 같은 의미를 가집니다.

 


이제 간단한 예제를 실습해보면서 변수를 사용해보도록 하겠습니다. 

 

using System;

namespace MyFirstApp
{
    class Program
    {
        static void Main(string[] args)
        {
            int a = 1_000_000_000;      // 자릿수를 구분할 때 _를 사용합니다.
            float b = 3.1734F;          // F는 float를 의미하며 이러한 리터럴을 만들 때 사용
            double c = 3.1734;          // double 형태는 F를 넣지 않아도 에러가 생기지 않는다.
            string d = "안녕 나야";

            Console.WriteLine(a);
            Console.WriteLine(b);
            Console.WriteLine(c);
            Console.WriteLine(d);

        }
    }

숫자를 사용할 때는 구분자인 '_'를 사용함으로써 사람이 보기 편하게 만들 수 있습니다.

1000000000 = 1_000_000_000 과 같이 쓰는 것이죠. 구분자를 어디에 둘지는 프로그래머가 정할 수 있지만, 통상적으로 3개의 자릿수 마다 구분자를 둡니다.

 

만약에 데이터형의 범위를 넘어가는 값을 대입하려고 한다면 컴파일러가 오류를 발생시킵니다. 

위에 코드에서 추가로

short e = 500000000;

을 넣게 되면 오류가 발생합니다. 

 

컴파일러가 잡지 못하는 오류에 대해서, 데이터형을 넘쳐서 데이터가 변형된 형태를 오버플로우라 부르며, 데이터형이 부족해서 생긴 변형을 언더플로우라 부릅니다. 

 

우리는 둘 중에서 오버플로우에 대한 예제만 살펴보도록 하겠습니다.

using System;

namespace MyFirstApp
{
    class Program
    {
        static void Main(string[] args)
        {
            short a = 32767;      // short의 최댓값은 32,767
            a++;                  // 1만큼 증가시킨다.

            Console.WriteLine(a);

        }
    }
}

실제 실행하게 되면, 32767이 나오는 것이 아닌 -32768이 나오게 됩니다. 데이터가 저장할 수 있는 한계선을 넘어감으로써 우리가 원하는 값이 아닌 다른 데이터 값을 표현하게 된 것입니다. 이 부분에 대해서도 나중에 저장 구조()에 대해 살펴보고 그 다음에 설명드리도록 하겠습니다. 

 

위의 구조를 조금 더 바꿔보도록 하겠습니다. 바로 전에 배웠던 short.MaxValue를 활용해보도록 하겠습니다. 

using System;

namespace MyFirstApp
{
    class Program
    {
        static void Main(string[] args)
        {
            short a = short.MaxValue;      // short의 최댓값은 32,767
            a++;                  // 1만큼 증가시킨다.

            Console.WriteLine(a);

        }
    }
}

언더플로우까지 나오게 한다면, 

using System;

namespace MyFirstApp
{
    class Program
    {
        static void Main(string[] args)
        {
            short a = short.MaxValue;      // short의 최댓값은 32,767
            a++;                  // 1만큼 증가시킨다.

            Console.WriteLine(a);

            a = short.MinValue;
            a--;
            Console.WriteLine(a);
        }
    }
}

로 바꿔 볼 수 있습니다. 

 


실수를 담은 데이터 형 float, double, decimal

  지금까지는 거의 정수형에 대한 이야기를 해왔습니다. 그렇다면 소수를 표현하는 수단은 어떻게 표현해야 하는가? 바로 float, double, decimal 형태로 표현합니다. 세 개의 데이터 형의 차이점은 데이터를 어디까지 표현할 수 있는가 입니다. 

 

  가장 많은 수를 표현할 수 있는 것은 float < double < decimal의 순으로 정밀도가 높습니다. 정밀도는 소수점을 표현할 수 있는 선을 이야기합니다. C#은 기본적으로 double형을 장려합니다. float보다 더 많은 데이터를 차지하지만, 데이터 손실을 안고 가는 것보다는 double형을 쓰면서 얻을 데이터를 확보하자는 것이죠. 하지만 더 높은 정밀도를 가진 decimal은 너무 과도한 정밀도 일수도 있기에 기본으로 쓰이는 것은 double형을 사용합니다. 

 

  실제로 예제를 통해 정밀도가 어디까지 표현되는지에 대해 살펴보도록 하겠습니다. 

using System;

namespace MyFirstApp
{
    class Program
    {
        static void Main(string[] args)
        {
            float a = 3.1415926535_8979323846_2643383279_5028841971f;   // float형을 사용하려면 숫자 뒤에 f가 필요하다.
            double b = 3.1415926535_8979323846_2643383279_5028841971;   // 
            decimal c = 3.1415926535_8979323846_2643383279_5028841971m; // decimal형을 사용하려면 숫자 뒤에 m이 필요하다.

            Console.WriteLine(a);
            Console.WriteLine(b);
            Console.WriteLine(c);
        }
    }
}

 

입력한 수는 파이를 입력해보았습니다. 10자리 마다 구분지어서 넣어보았습니다. 실제 실행 결과를 보면 float과 double, decimal에 따라 소수점 아래에 숫자를 표현하는 정도가 다름을 확인할 수 있습니다. (정밀도가 다른 것이죠)

 


글이 길어지는 관계로 다음 포스팅으로 넘어가서 글을 이어가도록 하겠습니다! 

감사합니다.

+ Recent posts