Search
Duplicate

뇌를 자극하는 C# 4.0 프로그래밍/ 데이터 보관하기

데이터에도 종류가 있다

데이터 형식은 ‘기본 데이터 형식 : 복합 데이터 형식’이나 ‘값 형식 : 참조 형식’으로 구분할 수 있다.

변수(Variable)

아래와 같이 변수를 선언하면 컴파일러는 선언된 int 형식을 위해 메모리 공간을 할당하고 이 공간을 x라는 식별자가 사용할 수 있도록 준비해 둔다.
선언된 변수에는 대입 연산자를 통해 데이터를 입력할 수 있는데 이 코드가 실행되면 x를 위해 할당된 메모리 공간에 데이터 100이 기록된다.

값 형식(Value Types)과 참조 형식(Reference Types)

값 형식은 변수가 값을 담고, 참조 형식은 변수가 값이 있는 곳의 위치(참조)를 담는다.
메모리 영역은 스택(Stack)과 힙(Heap)으로 구분할 수 있는데, 스택은 값 형식과 관련 있고, 힙은 참조 형식과 관련이 있다.

스택과 값 형식

스택은 먼저 들어간 데이터가 아래에 쌓이고 나중에 들어간 데이터가 위에 쌓이는 형식. 먼저 들어간 데이터를 꺼내려면 그 위에 쌓인 데이터들을 모두 걷어내야 한다.
값 형식의 변수들은 모두 스택에 저장된다.
코드 블록 안에 생성된 모든 값형 변수들은 코드 블록이 끝나면 —} 를 만나면– 메모리에서 제거된다.

힙과 참조 형식

스택은 자신이 담고 있던 데이터를 모두 제거하지만, 힙은 저장되어 있는 데이터를 스스로 제거하는 메커니즘이 없다. 힙의 데이터를 제거하는 역할은 CLR의 가비지 컬렉터가 담당 한다.
가비지 컬렉터는 프로그램 뒤에 숨어 동작하면서 힙에 더는 사용하지 않는 객체가 있으면 그 객체를 쓰레기로 간주하고 수거하는 기능을 한다.
힙이라는 메모리 영역이 필요한 이유는 코드 블록이 끝난 후에도 데이터를 유지하고 싶기 때문. 스택은 코드 블록이 끝나면 데이터가 사라지기 때문에 한계가 있다.
참조 형식의 변수는 힙과 스택을 모두 사용한다. 힙 영역에는 데이터를 저장하고, 스택 영역에는 데이터가 저장되어 있는 힙 메모리의 주소를 저장한다.
힙의 데이터를 참조 하고 있는 스택이 없으면 가비지 컬렉터가 수거해 간다.
여기서 중요한 점은 가비지 컬렉터가 힙의 쓰레기를 언제 수거해 갈지 알 수 없다는 것. 이 부분은 최적화 이슈와도 연결된다.

기본 데이터 형식(Primitive Types)

C#이 제공하는 기본 데이터 형식은 모두 15가지가 존재하는데, 이들은 크게 숫자 형식, 논리 형식, 문자열 형식, 오브젝트 형식으로 구분된다.
이 중 문자열 형식과 오브젝트 형식만 참조 형식이며 나머지는 모두 값 형식이다.

숫자 데이터 형식(Numeric Types)

프로그래밍을 구성하는 가장 많은 데이터 형식이 숫자. 이유는 다른 복잡한 데이터가 숫자를 기반으로 구성되기 때문.
텍스트 데이터도 알고 보면 각 문자 하나 하나가 내부적으로 숫자 코드로 구성되어 있다. ex) a는 63, b는 64

정수 계열 형식(Integral Types)

Search
데이터 형식
설명
크기(Byte)
담을 수 있는 값의 범위
sbyte
Open
signed byte 정수
1 (8 bit)
-128 ~ 127
short
Open
정수
2 (16 bit)
-32,768 ~ 32,767
ushort
Open
unsigned short 정수
2 (16 bit)
0 ~ 65535
int
Open
정수
4 (32 bit)
-2,147,483,648 ~ 2,147,483,647
uint
Open
unsigned int 정수
4 (32 bit)
0 ~ 4,294,967,295
long
Open
정수
8 (64 bit)
-922,337,203,685,477,508 ~ -922,337,203,685,477,507
ulong
Open
unsigned long 정수
8 (64 bit)
0 ~ 18,446,744,073,709,551,615
char
Open
유니코드 문자
2 (16 bit)

부호 있는 정수와 부호 없는 정수

부호가 있는 데이터 형식은 가장 앞에 있는 비트를 부호로 사용한다.
아래의 이미지는 -127일 것 같지만 사실은 -1 값이 된다. 이유는 그 아래의 설명 참조.
직관적으로 생각하기엔 음수는 맨 앞의 비트를 1로 표현하고 나머지는 본래 숫자 자체로 표현할 것 같은데 –이런 방법을 부호와 절대값 방식 (Sign-and-magnitude)이라고 한다– 이 방식을 사용하면 0이 +0(0000 0000)과 -0(1000 0000)으로 표현되는 문제가 발생한다.
이러한 문제를 해결하기 위해 음수 표현은 2의 보수법 (2’s Complement)이라는 방식을 사용하는데 그 표현 방법은 다음과 같다.
1.
먼저 수 부분 비트를 채운다.
2.
전체 비트를 반전 시킨다.
3.
반전된 비트에 1을 더한다.
아래의 이미지는 -1을 2의 보수법으로 표현한 예

데이터가 넘쳐 흘러요

데이터 형식의 크기를 넘어서는 값을 담게 될 때 나타나는 현상을 오버플로우 (Overflow)라고 한다.
byte의 최대값은 1111 1111(255)인데 여기에 1을 더하면 1 0000 0000이 된다. byte는 8개의 비트만 담을 수 있기 때문에 왼쪽의 비트는 버리고 오른쪽의 8개의 비트만 보관하기 때문에 byte 형식의 변수가 오버플로우가 되면 0이 된다.
이와 반대로 값 형식의 최저값보다 작은 데이터를 저장하면 언더플로우 (Underflow)가 일어난다.

부동 소수점 형식(Floating Point Types)

부동 소수점이란 소수점이 고정되어 있지 않고 움직이면서 수를 표현한다는 뜻이다.
이 때문에 부동 소수점 방식은 정밀도에 한계가 있음.
Search
데이터 형식
설명
크기(Byte)
담을 수 있는 값의 범위
float
Open
단일 정밀도 부동 소수점 형식 (7개의 자릿수만 다룰 수 있음)
4 (32 bit)
-3.402823e38 ~ 3.402823e38
double
Open
복수 정밀도 부동 소수점 형식 (15-16개의 자릿수를 다룰 수 있음)
8 (64 bit)
-1.79769313486232e308 ~ 1.79769313486232e308
부동 소수점 형식은 실수 영역의 데이터를 다룰 수 있지만 다음과 같은 이유로 정수 형식을 대체할 수 없다.
1.
소수점을 표현하기 위해 일부 비트를 사용하기 때문에 같은 크기의 정수 계열 형식과 같은 크기의 수를 표현할 수 없다.
2.
산술 연산 과정이 정수 계열 형식보다 복잡해서 느리다.
float 형식의 경우 맨 앞의 1비트를 부호 전용으로 사용하고, 그 다음 8비트를 소수점의 위치를 나타내는 지수부로 사용하고, 나머지 23비트를 수를 표현하는 가수부로 사용한다.
float는 3.402823e38(3.402823×1038)-3.402823e38(-3.402823 \times 10^{38}) ~ 3.402823e38(3.402823×1038)3.402823e38(3.402823 \times 10^{38})에 이르는 어마어마한 크기를 다룰 수 있지만 유효숫자는 7자리 밖에 되지 않는다. 7자리를 넘어가는 수는 ‘대략적으로’ 표현한다는 뜻.

Decimal 형식

Search
데이터 형식
설명
크기(Byte)
담을 수 있는 값의 범위
decimal
Open
29자리 데이터를 표현할 수 있는 소수 형식
16 (128 bit)
±1.0 x 10e-28 ~ ±7.9 x 10e28
decimal도 범위의 한계는 있지만, float이나 double보다 높은 정밀도를 나타내기 때문에 큰 수를 다뤄야 하는 경우에 유용하다.

문자 형식과 문자열 형식

char 형식은 정수를 다루는 데이터 형식이지만 문자 데이터를 다룬다.
작은 따옴표 '를 사용한다.
string은 여러 char가 묶여 있는 데이터 형식. string 형식은 참조형이기 때문에 정해진 크기나 담을 수 있는 데이터의 범위가 따로 정해져 있지 않다.
큰 따옴표 "를 사용한다.

논리 형식

Search
데이터 형식
설명
크기(Byte)
담을 수 있는 값의 범위
bool
Open
논리 형식
1 (8 bit)
true, false
C 언어에서는 논리 형식이 없었기 때문에 0을 거짓 0이 아니면 참으로 사용했었다.

object 형식

C#에서는 object가 모든 데이터를 다룰 수 있도록 모든 데이터 형식이 object 형식을 상속 받도록 정의해 놨다.

박싱(boxing)과 언박싱(unboxing)

object 형식은 값 형식의 데이터를 힙에 할당하기 위한 ‘박싱(boxing)’ 기능을 제공한다. object 형식에 값 형식의 데이터를 할당하려는 시도가 이루어지면 object 형식은 박싱을 수행해서 해당 데이터를 힙에 할당한다.
이와 반대로 힙에 있던 값 형식 데이터를 값 형식 객체에 다시 할당해야 하는 경우가 있는데 이를 ‘언박싱(unboxing)’이라고 한다.

데이터 형식 바꾸기

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

작은 정수 형식의 변수에 있는 데이터를 큰 정수 형식의 변수로 옮길 때는 문제가 없지만 그 반대의 경우 오버플로우가 발생할 수 있다. 물론 큰 변수로부터 옮겨오는 데이터가 작은 형식의 변수가 담을 수 있는 크기라면 문제 없다.

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

부동 소수점 형식의 특성상 float과 double의 사이의 변환에 오버플로우는 존재하지 않는다. 다만 정밀도에 손상이 생길 수는 있다.

부동 소수점 형식과 정수 형식 사이의 변환

부동 소수점 형식의 변수를 정수 형식으로 변환하면 데이터에서 소수점 아래는 버리고 소수점 위의 값만 남긴다. 0.1이나 0.9나 모두 정수 형식으로 변환하면 0이 된다.

문자열을 숫자로, 숫자를 문자열로

int a = int.Parse("12345"); float b = float.Parse("123.45"); string c = a.ToString();
C#
문자열을 숫자로, 숫자열을 문자로 변환하려고 하면 컴파일도 되지 않는다. 그러나 이 형식 변환은 매우 자주 있는 일이기 때문에 C#에서는 이 둘 사이의 변환에 위와 같은 별도의 방법을 마련해 주고 있다.
문자열을 int나 float 형식으로 바꿀 때는 Parse() 메소드를 사용하고, 숫자 형식을 문자열로 바꿀 때는 ToString() 메소드를 사용한다.

상수(Constants)와 열거 형식(Enumerator)

상수 – 전 언제나 변하지 않을 거에요

const int a = 3; const double b = 3.14; const string c = "abcde";
C#
상수는 const 키워드를 데이터 타입 앞에 붙이면 된다.
상수는 실행 중에 바꿀 수 없기 때문에 선언 시에 값을 넣어줘야 한다.

열거 형식 – 여러 개의 상수를 정리 합시다

// 열거형 선언 enum Dialog { Yes, No, Cancel, Confirm, OK } // 열거형 변수 사용 Dialog result = Dialog.Yes;
C#
실제 프로그래밍시에 대단히 유용한 자료형. 상수이고 범위가 제한적이기 때문에 대단히 안전하고, 사용할 때 위와 같이 문자 형태로 표현되기 때문에 직관성도 높다.
또한 각 열거형 상수가 값을 갖고 있기 때문에 숫자형 데이터로 변환하거나 숫자형 데이터를 열거형으로 바꾸는데도 문제가 없다.
따로 값을 대입할 수도 있지만 아무런 값도 넣지 않으면 컴파일러가 0부터 1씩 증가하여 알아서 값을 넣어준다.

Nullable 형식

int? a = null; float? b = null; doublie? c = null;
C#
기본적으로 값 형식의 변수는 null 값을 가질 수 없는데, 만일 값 형식의 변수가 null 값을 갖도록 하려면 위와 같이 형식 이름 뒤에 ?를 붙이면 된다.
이렇게 선언하면 컴파일러는 해당 변수에게 할당된 메모리 공간을 비워둔다.

var: 데이터 형식을 알아서 파악하는 똑똑한 C# 컴파일러

var a = 3; // a는 int 형식 var b = "Hello"; // b는 string 형식
C#
기본적으로 C#은 형식 검사를 강력하게 하는 언어이기 때문에 선언할 때 형식을 지정해 줘야 하지만 var 라는 키워드를 통해 어떠한 타입의 형식도 받을 수 있는 변수를 선언할 수 있다.
다만 var 타입의 변수는 선언할 때 반드시 값을 받아야 한다. 이는 컴파일 단계에서 컴파일러가 어떤 타입의 변수인지 알아야 하기 때문.
개인적인 성향상 var 키워드의 가독성이 떨어지고 엄격함이 떨어져서 선호하지 않는데, enumerator 형식의 복잡하게 중첩된 자료형의 경우 —List<Dictionary<int, string>>와 같은– var를 쓰면 타이핑을 줄일 수 있어서 편하긴 하다.

공용 형식 시스템(Common Type System)

System.Int32 a = 123; System.String c = "abc";
C#
공용 형식 시스템이란 .NET 프레임워크를 지원하는 모든 언어들이 따르는 데이터 형식 표준. .NET 언어들끼리의 호환성을 높이기 위해 도입되었다.
만일 위와 같이 변수를 선언하면 .NET 언어 어디서든 그대로 사용될 수 있다.
Search
Class Name
C# 형식
C++ 형식
비주얼 베이직 형식
System.Byte
Open
byte
unsigned char
Byte
System.SByte
Open
sbyte
char
SByte
System.Int16
Open
short
short
Short
System.Int32
Open
int
int 또는 long
Integer
System.Int64
Open
long
_int64
Long
System.UInt16
Open
ushort
unsigned short
UShort
System.UInt32
Open
uint
unsigned int 또는 unsigned long
UInteger
System.UInt64
Open
ulong
unsigned _int64
ULong
System.Single
Open
float
float
Single
System.Double
Open
double
double
Double
System.Boolean
Open
bool
bool
Boolean
System.Char
Open
char
wchar_t
Char
System.Decimal
Open
decimal
Decimal
Decimal
System.IntPtr
Open
없음
없음
없음
System.UIntPtr
Open
없음
없음
없음
System.Object
Open
object
Object*
Object
System.String
Open
string
String*
String