본문 바로가기
전공/C# 프로그래밍

2강. 데이터 타입 (2)

by 임 낭 만 2023. 4. 15.

기본 데이터 형식

부호 있는, 부호 없는 정수 형식

  • 부호 있는 정수형
    • 음수(-), 0, 양수(+)
    • sbyte, short, int, long
  • 부호 없는 정수형
    • 0, 양수(+)
    • byte, ushort, uint, ulong
  • byte와 sbyte 비교
    • 두 형식 모두 1 바이트, 즉 8 비트로 구성
    • byte는 1~255 표현, sbyte는 -128~127 표현

byte 형의 비트표현

sbyte 형의 음수 표현 : 2의 보수

  • sbyte의 비트표현
    • 0과 양수의 비트표현은 byte와 동일
    • 음수 비트표현은 2의 보수법 이용

sbyte의 비트 표현

예제 코드

using System;

namespace SignedUnsigned
{
    class Program
    {
        static void Main(string[] args)
        {
            byte a = 255;       // 비트표현: 1111 1111 
            sbyte b = (sbyte)a;

            byte c = 128;       // 비트표현: 1000 0000 
            sbyte d = (sbyte)c; // sbyte의 범위 -128 ~ 127

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

더보기
더보기
  • 먼저, byte 변수 a에 255를 대입함. byte는 부호 없는 8비트(0~255) 정수를 표현하는 타입. 이진수로 나타내면 1111 1111임. 그리고 sbyte 변수 b에 byte 변수 a를 형변환하여 대입. sbyte는 부호 있는 8비트(-128~127) 정수를 표현하는 타입. 하지만 a의 값 255는 sbyte의 범위를 벗어나므로 형변환시 overflow가 발생. 결과적으로 b에는 -1이 저장됨.
  • 다음으로, byte 변수 c에 128을 대입. 이진수로 나타내면 1000 0000이 됨. 그리고 sbyte 변수 d에 byte 변수 c를 형변환하여 대입. c는 부호 없는 정수이지만, d는 부호 있는 정수이므로 형변환시에도 overflow가 발생. 결과적으로 d에는 -128이 저장됨.
  • Console.WriteLine 메서드를 사용하여 a, b, c, d 변수를 출력. a는 255, b는 -1, c는 128, d는 -128이 출력됨.

오버플로 (Overflow)와 언더플로 (Underflow) 예제 코드

using System;
using System.Formats.Asn1;

namespace OverflowUnderflow
{
    class Program
    {
        static void Main(string[] args)
        {
            uint a = uint.MaxValue; // uint형 최대값 4294967295
            Console.WriteLine(a);            
            a = a + 1;              // 0000 0000 … … 0000
            Console.WriteLine(a);

            int b = int.MaxValue;   // int형 최대값 2147483647
            Console.WriteLine(b);
            b = b + 1;              // 1000 0000 … … 0000
            Console.WriteLine(b);
        }
    }
}

오버플로우 (Overflow) : 각 데이터 형식의 최대값을 넘어가는 데이터를 적당할 때 / 언더플로우 (Underflow) : 최저값보다 작은 데이터를 저장할 때

더보기
더보기
  • uint 형식 변수 a에 uint 형식의 최대값을 할당. uint는 32비트 부호 없는 정수형이며, 최대값은 2^32-1이므로 a는 4294967295. Console.WriteLine() 메서드를 사용하여 a의 값을 출력됨.
  • a에 1을 더하기. uint 형식의 최대값에 1을 더하면 0이 됨. uint 형식이 부호 없는 32비트 정수형이기 때문. 32비트 중 가장 높은 자리수는 부호를 나타내는 비트가 아니라 숫자 값을 나타내는 비트이며, 부호가 없기 때문에 이 비트를 사용하여 음수를 나타낼 수 없음. 따라서 uint 형식에서는 숫자가 최대값에 도달하면 다시 0부터 시작하게 됨. Console.WriteLine() 메서드를 사용하여 a의 값을 출력하면 0이 출력됨.
  • int 형식 변수 b에 int 형식의 최대값을 할당. int는 32비트 부호 있는 정수형이며, 최대값은 2^31-1이므로 b는 2147483647. Console.WriteLine() 메서드를 사용하여 b의 값을 출력.
  • b에 1을 더하기. int 형식에서는 부호 비트를 사용하여 양수와 음수를 나타내므로, 최대값에 1을 더하면 부호 비트가 1이 되어 음수가 됨. b의 값이 1000 0000 ... ... 0000이 됨. Console.WriteLine() 메서드를 사용하여 b의 값을 출력하면 -2147483648이 출력됨.

부동 소수점 형식

  • 소수점이 고정되어 있지 않고 움직이면서 수를 표현
  • 정수와 유리수 포함
    • 정수 데이터형과 지원하는 값의 범위가 다름
    • 산술 연산과정이 복잡
  • 정밀도
    • float < double < decimal
    • decimal 형은 부동소수점형(float, double)과 다른 방식으로 소수를 다룸

float 형 비트 표현 : IEEE754

  • float과 double 형은 IEEE754 알고리즘 기반
  • 예: float 형 데이터 “10000.625f”의 비트표현
    • 2진수로 변환 → “10 0111 0001 0000.101”
    • 부동 소수점 형식으로 표현 → “1.0011100010000101 x 2^13
    • 지수부 8비트는 13+127=140 (즉, 2진수 “1000 1100”)
    • 나머지 가수부는 소수점 이하자리 “0011100010000101

float형 데이터의 비트 표현은 부호, 지수, 가수로 구성됨. 부호는 1비트이며 0은 양수, 1은 음수를 나타낸다. 지수는 8비트로 표현하며, 부동 소수점 데이터의 크기와 소수점 이동에 사용됨. 이 비트는 지수 표현 방식인 부호화된 지수 표현법을 사용함. 가수는 23비트로 표현하며, 부동 소수점 데이터의 소수점 이하 자릿수를 저장

더보기
더보기
  1. 10진수에서 2진수로 변환 
    정수 부분 : 10 0111 0001 0000 / 소수 부분 : 0.101
  2. 정규화 (부동 소수점 표현에서는 1.xxx * 2^y 형태)
    1.0001100010000101 × 2^13
  3. 지수부가 8비트이고, 양수만 표현 가능하기 때문에 2^7-1 즉, 127을 지수부인 13과 더하면 140이 됨.

부동 소수점 형식 예제 코드

using System;

namespace FloatingPoint
{
    class Program
    {
        static void Main(string[] args)
        {
            // 숫자 뒤에 f를 붙이면 float 형식으로 간주
            float a = 3.1415_9265_3589_7932_3846_2643_3832f;
            // 숫자 뒤에 아무 것도 없으면 double 형
            double b = 3.1415_9265_3589_7932_3846_2643_3832;
            // 숫자 뒤에 m을 붙이면 decimal 형식으로 간주
            decimal c = 3.1415_9265_3589_7932_3846_2643_3832m;

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

문자 형식과 논리 형식

  • char 형
    • 정수 계열의 형식이지만, ‘가’ ‘나’ ‘a’ ‘b’ 와 같은 문자 데이터를 다룸
    • ushort와 비트 상으로 16비트로 동일
    • 사칙연산 수행 시 컴파일 에러

  • 논리 형식
    • 참 또는 거짓 데이터를 다룸

object 형식

  • 어떤 데이터이든지 다룰 수 있는 형식
    • 모든 데이터 형식이 object 형식으로부터 상속 받음

상속의 효과임. 참조 형식이므로 힙에 데이터를 할당함. object는 모든 데이터 형식의 조상이므로 모든 데이터 형식을 담을 수 있음.

using System;

namespace Object
{
    class Program
    {
        static void Main(string[] args)
        {
            object a = 123;					//int형
            object b = 3.1415_9265_3589_7932_3846_2643_3832m;	//decimal 형
            object c = true;					//bool 형
            object d = "안녕하세요.";				//string 형
            
            Console.WriteLine(a);
            Console.WriteLine(b);
            Console.WriteLine(c);
            Console.WriteLine(d);
        }
    }
}

박싱과 언박싱

  • 박싱 (Boxing)
    • 값 형식의 데이터를 힙에 할당 방법

  • 언박싱 (Unboxing)
    • 박싱된 값을 꺼내 값 형식 변수에 저장하는 과정

using System;

namespace BoxingUnboxing
{
    class Program
    {
        static void Main(string[] args)
        {
            int a = 123;
            object b = (object)a;	//a에 담긴 값을 박싱해서 힙에 저장
            int c = (int)b;            	//b에 담긴 값을 언박싱해서 스택에 저장	

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

            double x = 3.1414213;
            object y = x;		//x에 담긴 값을 박싱해서 힙에 저장
            double z = (double)y;	//y에 담긴 값을 언박싱해서 스택에 저장

            Console.WriteLine(x);
            Console.WriteLine(y);
            Console.WriteLine(z);
        }
    }
}

더보기
더보기

박싱 (Boxing), 언박싱 (Unboxing)

  • 박싱 : 값 형식을 object 형식에 담아 힙에 올리기
  • 언박싱 : 힙에 올라가 있는 데이터를 object에서 꺼내 값 형식으로 옮기기
  • ex) object a = 20;

데이터 형 바꾸기

데이터형 변환

  • 암시적 변환
    • 범위가 작은 데이터 타입에서 범위가 큰 타입으로 변환
    • 부가적인 코드를 지정하지 않고 형변환
byte b = 250; 	// byte 범위 0~255
short s = b; 	// short 범위 -32,768 ~ 32,767
  • 명시적 변환
    • 개발자가 의도한 형변환임을 컴파일러에 알리는 변환
    • 예: 개발자가 의도하여 char 형 변수에 ‘A’의 숫자 값 65 입력
ushort u = 65; 		// ‘A’의 숫자 값은 65 
char c = (char)u; 	// char 형에 숫자를 그대로 입력하면 에러 발생
Console.WriteLine(c); 	// 출력 결과: A

크기가 서로 다른 정수형 사이의 변환

using System;

namespace IntegralConversion
{
    class Program
    {
        static void Main(string[] args)
        {
            sbyte a = 127;
            Console.WriteLine(a);

            int b = a;      // 암시적 형변환 
            Console.WriteLine(b);

            int x = 128;    // sbyte의 최대값 127보다 1 큰 수
            Console.WriteLine(x);

            sbyte y = (sbyte)x; // 명시적 형변환 후 오버플로 발생
            Console.WriteLine(y);
        }
    }
}

크기가 다른 부동 소수점 형식 사이 변환

  • float 형과 double 형 모두 소수를 2진수로 메모리에 저장
  • float 형과 double 형 사이의 변환
    • 메모리에 저장된 2진수를 10진수로 복원 후, 다시 2진수로 변환
    • 2진수로 모든 소수를 완벽 표현 불가능, 두 데이터형 사이 변환 시 정밀도에 손상 발생 가능

부동소수점 형식의 특성상 오버플로우는 존재하지 않지만, 정밀성에 손상을 입음. 이진수로 표현하는 소수는 완전하지 않기 때문.

부호 있는, 부호 없는 정수형 사이 변환

  • 변환에 참여하는 두 정수형의 값 범위를 유의
    • 변환 전, 오버플로 또는 언더플로 발생하는지 확인 필요
using System;

namespace SignedUnsignedConversion
{
    class Program
    {
        static void Main(string[] args)
        {
            int a = 500;
            Console.WriteLine(a);

            uint b = (uint)a;
            Console.WriteLine(b);

            int x = -30;
            Console.WriteLine(x);

            uint y = (uint)x;   // 언더플로 발생
            Console.WriteLine(y);
        }
    }
}

부동 소수점형에서 정수형으로 변환

  • 부동 소수점형 변수는 정수형 범위 내의 값을 사용
  • 정수형으로 변환 시 소수점 이하 버림  (반올림 없음)
using System;

namespace FloatToIntegral
{
    class Program
    {
        static void Main(string[] args)
        {
            float a = 0.9f;
            int b = (int)a;
            Console.WriteLine(b);

            float c = 1.1f;
            int d = (int)c;
            Console.WriteLine(d);
        }
    }
}

문자열과 숫자 사이의 변환

  • 명시적 변환 시 컴파일 에러 발생

  • “Parse (∙)” 메소드
    • 숫자로 반환할 문자열을 숫자로 변환
    • 모든 정수, 부동 소수점 형식에서 지원되는 메소드
  • “ToString ()” 메소드
    • 숫자로부터 문자열 출력
    • object로부터 상속 받은 ToString() 메소드를 재정의
using System;

namespace StringNumberConversion
{
    class Program
    {
        static void Main(string[] args)
        {
            int a = 123;
            string b = a.ToString();
            Console.WriteLine(b);

            float c = 3.14f;
            string d = c.ToString();
            Console.WriteLine(d);

            string e = "123456";
            int f = int.Parse(e);	//int f = Convert.ToInt32(e)도 가능
            Console.WriteLine(f);

            string g = "1.2345";
            float h = float.Parse(g);
            Console.WriteLine(h);             
        }
    }
}


상수와 열거 형식

상수와 열거 형식

  • 상수와 열거 형식은 안에 담긴 데이터를 변경 불가
  • 상수의 선언은 변수의 선언과 유사

  • 열거 형식은 여러 개의 상수를 선언

  • 기반 자료형은 정수 계열
    • byte, sbyte, short, ushort, int, uint, long, ulong, char
    • 생략할 경우 컴파일러는 int 자료형 사용
  • 열거 형식 안에 선언된 상수에 값 할당이 없는 경우
    • 각 상수에 0부터 자동으로 1씩 증가하여 차례로 할당

열거 형식 상수 값 할당

  • 열거형식 선언 시 개발자가 상수 값 할당 가능
    • 값이 할당 되지 않은 상수는 앞 상수 값에 1을 더한 값
    • 맨 앞 상수가 할당되지 않은 경우 0으로 자동 할당
using System;

namespace Enum
{
    class Program
    {
        enum DialogResult {YES , NO, CANCEL = 50, CONFIRM, OK}

        static void Main(string[] args)
        {
            Console.WriteLine((int)DialogResult.YES);
            Console.WriteLine((int)DialogResult.NO);
            Console.WriteLine((int)DialogResult.CANCEL);
            Console.WriteLine((int)DialogResult.CONFIRM);
            Console.WriteLine((int)DialogResult.OK);
        }
    }
}

열거 형식의 변수 생성

  • 열거 형식의 선언은 새로운 데이터형식의 생성 의미
    • 선언된 열거형식을 통해 변수 생성 가능
    • 변수에는 열거형식에서 정의 된 상수만 담을 수 있음
using System;

namespace Enum2
{
    class Program
    {
        enum DialogResult { YES, NO, CANCEL, CONFIRM, OK}
        static void Main(string[] args)
        {
            DialogResult result = DialogResult.YES;

            Console.WriteLine(result == DialogResult.YES);
            Console.WriteLine(result == DialogResult.NO);
            Console.WriteLine(result == DialogResult.CANCEL);
            Console.WriteLine(result == DialogResult.CONFIRM);
            Console.WriteLine(result == DialogResult.OK);
        }
    }
}

더보기
더보기

열거형식 (Enumerated Type)

  • 하나의 이름 아래 묶인 상수들의 집합
  • 종류는 같지만 다른 값을 갖는 상수 : 같은 범주에 속하는 여러 개의 상수를 선언 할 
  • enum 키워드를 이용하여 선언

상수와 열거 형식은 데이터를 절대 바꿀 수 없는 메모리 공간임. 


Nullable 형식과 var 키워드

Nullable 형식

  • 값 형식의 변수가 “비어있는 상태가” 될 수 있는 형식
  • 원래 데이터 형에 ‘?’를 붙여서 선언

  • Nullable 형식 변수에 값 할당 없이 사용하면 컴파일 에러 발생
    • null 또는 해당 데이터 형 범위 내의 값 할당 가능
  • HasValue와 Value 속성을 가짐
    • HasValue: 해당 변수가 값을 가지고 있는지 확인
    • Value: 변수에 담겨 있는 값

HasValue와 Value 예제 코드

using System;

namespace Nullable
{
    class Program
    {        
        static void Main(string[] args)
        {            
            int? a = null;
            Console.WriteLine(a.HasValue);
            Console.WriteLine(a != null);
            //Console.WriteLine(a.Value); 런타임 에러 발생 (null 할당되어 있음)

            a = 3;
            Console.WriteLine(a.HasValue);
            Console.WriteLine(a != null);
            Console.WriteLine(a.Value);

            //int? b;
            //Console.WriteLine(b.HasValue); 컴파일 에러 발생 (초기화 필요)
        }
    }
}

Var 키워드

  • 변수를 선언하면 컴파일러가 자동으로 해당 변수의 형식 지정
    • 변수 선언과 동시에 초기화 필요
    • 초기화 데이터에 따라 해당 변수의 형식 지정
    • 지역 변수로만 사용할 수 있음

  • var 키워드와 object 형식과의 차이점
    • 예를 들어, “var a = 3;”과 “object a = 3;”를 비교하면,
    • object 형식의 경우 CLR이 3을 박싱해서 힙에 넣고 a 가 힙을 가리키도록 설정
    • var 키워드의 경우 컴파일 시점에서 a의 데이터형을 int로 바꿔 컴파일

CTS 표준 데이터형

CTS의 데이터 형식

  • 공용형식 시스템 (CTS)
    • 모든 .NET 호환 언어들이 따르는 데이터 형식 표준
    • CTS에서 정의하는 데이터형식을 모두 구현할 필요는 없음
    • C# 의 데이터 형식 체계가 CTS 표준을 따름
    • CTS 의 데이터형식은 코드에서 그대로 사용 가능

CTS 데이터 형식 예제 코드

using System;

namespace CTS
{
    class Program
    {
        static void Main(string[] args)
        {
            System.Int32 a = 123;
            int b = 456;
            Console.WriteLine("a type:{0}, value:{1}", a.GetType(), a);
            Console.WriteLine("b type:{0}, value:{1}", b.GetType(), b);

            System.String c = "abc";
            string d = "def";
            Console.WriteLine("c type:{0}, value:{1}", c.GetType(), c);
            Console.WriteLine("d type:{0}, value:{1}", d.GetType(), d);
        }
    }
}

'전공 > C# 프로그래밍' 카테고리의 다른 글

5강. 코드 흐름 제어  (0) 2023.04.16
4강. 데이터 가공을 위한 연산자  (1) 2023.04.16
3강. 문자열 다루기  (0) 2023.04.16
2강. 데이터 타입 (1)  (2) 2023.04.14
1강. C# 언어와 .NET 플랫폼 소개  (0) 2023.04.13

댓글