[C# 기초강좌] 6. C# 자료형
이 글은 제가 과거에 운영했던 사이트인 http://dotnet.mkexdev.net 의 글을 옮겨온 것입니다. 원본 글은 2010년에 작성되었습니다.
그 전에 운영했었던 사이트(mkex.pe.kr)은 흔적도 없이 사라 졌습니다. 그속의 글들도 모두... 그래서 이 사이트도 사라지기 전에 옮기고 싶은 글을 조금씩 이 블로그로 이동시키려 합니다.
(원본글) http://dotnet.mkexdev.net/Article/Content.aspx?parentCategoryID=1&categoryID=5&ID=670
이 글은 닷넷 기초 지식을 전파하기 위해 2010경에 작성되었으며, 당시 윤성우의 프로그래밍 스터디그룹 네이버 카페에도 필진으로 참여하여 연재했던 글이기도 합니다. 현재 시점에서 조금 달라진 부분이 있을 수 있으나 기본 원리와 언어 기초에 해당하는 부분은 크게 변하지 않았을 것으로 생각하며 이런 부분들을 감안해서 봐 주시기 바랍니다.
“C#은 자료는 값 타입과 참조타입으로 나누어 집니다”
안녕하세요. 박종명입니다. 닷넷 여섯 번째 강좌를 진행하도록 하겠습니다.
강좌가 좀 늦어졌네요. 개인적 사유로 조금 정신 없는 하루하루를 보내고 있네요. 죄송합니다 ^^;
이번 주제는 C# 의 자료형(Data Type)에 대해 살펴보도록 하겠습니다.
C#의 자료형 역시 자바와 크게 다르지 않습니다.
자료형은 말 그대로 자료(Data)의 형식(Type) 입니다
프로그램에서 다루고자 하는 자료가 숫자인지 문자인지를 구분하고 얼마만큼의 저장공간이 필요한지 그리고 나타낼 수 있는 최대값과 최소값은 어떻게 되는지 등의 정보가 포함되는 것이 바로 형식(Type)정보 입니다.
C#은 강력한 형식의 언어입니다.
모든 자료는 정확한 형식이 정의되어야 하며 형식에 맞도록 값이 저장되어야 합니다.
또한 자료간 형식 변환도 엄격한 기준에서 이루어지도록 하여 형식 안정성이 보장되도록 합니다
CTS(Common Type System, 공용형식시스템)
닷넷에서 이러한 형식에 관한 세부 스펙을 정의한 것을 CTS라고 합니다. CTS는 CLR에 포함된 형식 시스템으로 런타임에서 형식을 정의하고 사용 및 관리하는 기준과 방법을 정의해 놓은 일종의 사양입니다. 또한 언어간 통합에 있어 언어간 상호 작용할 수 있도록 따라야 할 규칙도 정의하고 있습니다
형식의 분류
자료 형식을 분류하는 기준은 그 관점에 따라 조금씩 달라질 수 있습니다. 보통 많이 쓰는 문자형식, 숫자형식은 언어사양에서 기본으로 제공해 주는 자료형입니다.
반면 구조체나 클래스는 사용자가 입맛에 맞게 적절히 구성할 수 있는 특수한 자료형입니다.
이런 관점이라면 ‘기본 제공 자료형 vs 사용자 정의 자료형’ 으로 분류할 수 있겠습니다
또 한편으로는, 시스템이 자료를 어떻게 처리하는지, 즉 자료의 메모리 할당 방식과 복사 메커니즘이 어떻게 되는지에 대한 관점이라면 ‘값 형식과 참조 형식’으로 분류할 수 있겠습니다.
더 세부적인 관점이 더 있겠습니다만, 더 이상은 불필요 해 보입니다. 자료형식의 분류 기준은 이렇듯 두 가지 관점에서 바로 보는 것으로 충분해 보입니다
기본제공 자료형과 사용자정의 자료형
우리가 흔히 많이 쓰는 숫자나 문자 같은 자료는 언어에서 기본으로 제공해 주는 자료형입니다. 즉 int, double, char 등의 자료형은 시스템이 미리 정의해 둔 자료형이며 이를 Built-in Type 이라고 합니다.
반면 구조체와 클래스처럼 개발자가 커스텀하게 구성할 수 있는 자료형을 사용자정의자료형이라 하는데 User-Defined Type 이라고 합니다
값 형식과 참조 형식
CTS에서는 자료 형식을 크게 값 형식(Value Type)과 참조형식(Reference Type) 두 가지로 구분하고 있습니다
값 형식은 할당된 메모리에 데이터를 직접 포함하는 형태인 반면 참조 형식은 데이터가 저장된 메모리에 대한 참조 값이 저장되는 형태(포인터와 유사) 입니다
값 형식(Value Type)
값 형식은 위 그림처럼 ‘10’이라는 자료 값이 메모리에 직접 저장되는 구조이며 스택 메모리 영역에 저장됩니다.
또한 C#의 모든 값 형식은 암시적으로 System.ValueType 클래스를 상속받게 됩니다
닷넷 프레임워크에는 기본 값 형식을 위한 구조체가 이미 정의되어 있습니다. 예를 들어 int 키워드에 해당하는 구조체는 System.Int32 이며 이 때 int 키워드는 이 구조체의 별칭입니다
값 형식 내부에서도 다른 관점으로 보면 기본 제공 자료형과 사용자 정의 자료형으로 나눌 수 있는데요.
정수, 실수, 참/거짓(부울식), 문자와 같은 값 형식은 시스템이 기본적으로 정의해 둔 자료형이며 구조체, 열거형과 같은 값 형식은 사용자가 커스텀하게 정의할 수 있는 사용자정의자료형입니다
C#에서는 기본자료형을 위한 구조체들을 미리 정의하고 있으며 사용자정의형을 위해 enum, struct 키워드를 제공합니다. 아래는 값 형식을 설명하는 표입니다
형식 | 설명 | 표현 가능 범위 |
bool | 부울 값(true 또는 false) | true 또는 false |
byte | 부호 없는 8bit 정수 | 0 ~ 255 |
sbyte | 부호 있는 8bit 정수 | -128 ~ 127 |
char | 유니코드 16bit 문자 | U+0000 ~ U+ffff |
short | 부호 있는 16bit 정수 | -32,768 ~ 32,767 |
int | 부호 있는 32bit 정수 | -2,147,483,648 ~ 2,147,483,647 |
long | 부호 있는 64bit 정수 | -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 |
ushort | 부호 없는 16bit 정수 | 0 ~ 65,535 |
uint | 부호 없는 32bit 정수 | 0 ~ 4,294,967,295 |
ulong | 부호 없는 64bit 정수 | 0 ~ 18,446,744,073,709,551,615 |
float | 단정밀도 32bit 부동 소수점 숫자 | -3.402823e38 ~ 3.402823e38 |
double | 배정밀도 64bit 부동 소수점 숫자 | -1.79769313486232e308 ~ 1.79769313486232e308 |
decimal | 10진수 128bit 값 | -79,228,162,514,264,337,593,543,950,335~ 79,228,162,514,264,337,593,543,950,335 |
enum | 열거형 | (사용자 정의) |
struce | 사용자 정의 구조체 | (사용자 정의) |
값 형식이 null 일 수 있나?
기본적으로 값 형식은 null 일 수 없습니다
모든 값 형식은 기본 값이 제공되어야 하며 명시적으로 기본값을 지정하지 않으면 자동으로 정의된 기본 값이 저장됩니다. 다음 표는 초기화 되지 않은 변수에 대한 자동 기본 값 목록입니다.
값 형식 | 기본 값 | 값 형식 | 기본 값 |
bool | false | byte(sbyte) | 0 |
char | ‘\0’ | decimal | 0.0M |
double | 0.0D | enum | E(0) |
float | 0.0F | int(uint) | 0 |
long(ulong) | 0L | struct | 값 필드: 기본 값 참조형식 필드: null |
다만 조금 예외적인 상황이 있는데요.. 바로 nullable 타입일 경우 값 형식도 null 일 수 있습니다
nullable 타입은 닷넷 2.0 언어스펙에 추가된 내용인데요. 값 형식에도 null 을 할당할 수 있도록 하는 편리성이 추가되었습니다. ‘?’ (물음표) 키워드를 사용하여 정의하며 int?i = null 과 같이 허용됩니다
참조 형식(Reference Type)
참조 형식은 메모리에 자료 값이 직접 저장되는 것이 아니라 자료 값이 저장된 메모리에 대한 참조 값이 저장되는 구조입니다. 또한 이러한 참조 형식의 인스턴스는 힙(Heap) 메모리 영역에 저장됩니다
참조 형식 역시 기본 제공 자료형과 사용자 정의 자료형으로 구분할 수 있는데요
object 객체나 문자열을 나타내는 string 객체가 바로 닷넷이 기본으로 제공해 주는 기본 참조형식 자료입니다.
반면 클래스에 기반한 객체 및 인터페이스(interface), 델리게이트(delegate)는 사용자 정의 참조형식이라 할 수 있습니다. 또한 배열 역시 참조형식인데요. 배열의 요소가 값 형식이라 할지라도 모든 배열은 참조형식이 됩니다.
참조형식의 인스턴스는 new 연산자에 의해 메모리에 동적 할당이 되는데요.
C++ 과는 다르게 참조형식 자료의 해제는 명시적으로 개발자가 수행할 수 없습니다. 즉 닷넷 환경에서는 동적 객체의 메모리 해제는 개발자 대신 CLR의 가비지컬렉터라는 별도의 메커니즘에 의해 자동 관리됩니다.
동일성비교
두 자료가 같은 자료인지 비교하는 동일성 비교에 있어 값 형식과 참조형식은 다르게 동작합니다.
C#에서는 두 자료의 동일성 비교를 위해 ‘==’ 연산자를 제공하는데요
비교 대상 자료가 값 형식일 경우에는 자료의 값 자체를 비교하지만 참조형식인 경우에는 참조 값을 비교하게 됩니다. 아래 그림과 같이 값 형식인 두 자료 10을 비교하면 값 자체를 비교하기에 동일하다고 봅니다.
그러나 아래와 같이 참조형식일 경우에는 참조된 자료가 비록 같은 값이 가진 자료라 하더라도 참조 값이 다르기에 동일하지 않습니다.
참조형식이 동일 하려면 다음과 같은 구조이어야 합니다.
이러한 상황을 코드로 보면,
MyClass ob1 = new MyClass(10);
MyClass ob2 = new MyClass(10); //이 두 자료의 비교 ob1 == ob2 는 성립하지 않습니다
//대신
MyClass ob1 = new MyClass(10);
MyClass ob2 = ob1 //이 두 자료의 비교 ob1 = ob2 는 성립합니다
string 객체의 동일성 비교
앞서 말씀 드렸듯이 string 키워드는 문자열을 표현하기 위해 닷넷이 기본으로 제공하는 참조형식 자료입니다.
string 은 비록 참조형식 이지만 동일성 비교에 있어서는 값 형식처럼 동작합니다.
즉 string s1 =”hello” 와 string s2 = “hello” 로 선언하면 이 둘은 서로 다른 메모리에 할당되고 참조 값도 서로 다른 객체이지만 s1 = s2로 비교하면 동일하다는 결과가 나옵니다
이 것은 string 클래스 내부적으로 == 연산자를 오버로딩 하여 그 값 자체를 비교하도록 하기 때문입니다
자료 전달 및 복사
한 자료를 다른 자료에 대입하거나 함수의 매개변수로 전달할 경우 값 형식과 참조 형식은 다르게 동작합니다. 값 형식은 값 자체가 복사되어 전혀 새로운 값이 되지만 참조 형식은 참조 값이 복사되어 동일한 자료를 바라보게 됩니다.
아래 코드와 같이 int a를 선언하고 b 에 a를 대입하면 a의 값이 복사되어 b의 메모리 영역에 위치하게 됩니다. 즉 a 와 b는 각각 다른 메모리에 위치한 서로 다른 값으로써 b 값의 증가는 a 값에 영향을 주지 않습니다.
int a = 10;
int b = a;
b++;
그러나 아래 코드처럼 참조형식을 대입하게 되면 참조 값이 복사되어 결국 ob1과 ob2는 같은 객체를 바라보게 됩니다. 따라서 ob2의 멤버 값 증가는 ob1의 증가와 동일하게 됩니다.
MyClass ob1 = new MyClass(10);
MyClass ob2 = ob1;
ob2.a++;
이 것은 함수의 매개변수 전달에도 똑 같이 적용됩니다.
public void MyMethod(int i) 와 public void MyMethod(MyClass ob) 와 같은 형태의 함수에 각각 값 형식과 참조 형식이 전달된다고 할 경우 원리는 동일합니다. (ref 및 out 등 키워드를 사용할 경우에는 조금 달라집니다. 다음에 기회가 되면 알아보겠습니다)
지금까지 C#의 자료형에 대해 살펴보았습니다.
자료형과 관련하여 박싱/언박싱 및 가비지컬럭션, 값에 의한 전달, 참조에 의한 전달, 형 변환 등 더 다루어야 할 내용이 있으나 너무 길어지고 방대해지는 것 같아 이 정도로 정리하겠습니다.
이러한 내용들은 다음 강좌를 진행하면서 필요하면 상세히 다루도록 하겠습니다.
아래 그림은 지금까지 살펴본 자료형의 계층 구조를 보여줍니다
그럼 오늘 하루도 즐겁게 보내세요~~