[C# 개념] 3.4 기본 데이터 형식
- 값 형식 : 숫자 형식 ,논리 형식
- 참조 형식: 문자열 형식, 오브젝트 형식
3.4.1.숫자 데이터 형식
- c#은 15가지 기본 데이터 형식중 12가지를 숫자데이터 형식으로 제공
- 12가지 형식은 다시 정수 계열, 부동 소수 계열, 소수 계열 으로 나눠진다.
1) 정수 계열 형식
- 정수 데이터를 담기 위해 사용
- 12가지 형식중 9가지가 정수 계열 형식
- c# 은 pc나 대형 서버와 같이 메모리가 풍부한 컴퓨터를 위한 소프트웨어 뿐 아니라 휴대 전화기 같은 메모리가 아주 귀한 스마트 디바이스용 소프트웨어를 만드는 데도 쓰는 언어.
2) 정수 형식 예제 프로그램
using System;
using System.Formats.Asn1;
namespace IntegralTypes
{
class MainApp
{
static void Main(string[] args)
{
sbyte a = -10;
byte b = 40;
Console.WriteLine($"a={a}, b={b}");
short c = -30000;
ushort d = 60000;
Console.WriteLine($"c={c},d={d}");
int e = -1000_0000;
uint f = 3_0000_0000;
Console.WriteLine($"e={e}, f={f}");
long g = -5000_0000_0000;
ulong h = 200_0000_0000_0000_0000;
Console.WriteLine($"g={g},h={h}");
}
}
}
3) 2진수, 10진수 16진수 리터럴
- C# 은 2진수 리터럴을 위해 0b, 16진수 리터럴을 위해 0X 접두사를 제공합니다.
using System;
namespace IntegerLiterals
{
class MainApp
{
static void Main(string[] args)
{
byte a = 240;
Console.WriteLine($"a={a}");
byte b = 0b1111_0000;
Console.WriteLine($"b={b}");
byte c = 0XF0;
Console.WriteLine($"c={c}");
uint d = 0x1234_abcd;
Console.WriteLine($"d={d}");
}
}
}
4) 부호 있는 정수 와 부호 없는 정수
- 부호 있는 정수 : sbyte,short,int,long
- 부호 없는 정수 : byte, ushort,uint,ulong
- byte 는 비트 8개 모두를 수 표현에 사용하는 반면 sbyte는 8개중 7개 비트만 수표현에 사용하고 첫번째 비트는 부호 비트로 사용한다.
- 정답은 3번
- 부호 비트를 순수하게 음과 양을 나타내는 데 사용하고 나머지 비트도 순수하게 수를 나타내는 데만 사용하면 -127인데 이러한 방식을 부호와 절댓값 방식 => 0을 표현할때 +0(0000 0000) 과 -0(1000 0000) 두가지가 존재하는 문제가 발생
- 그리하여 sbyte는 2의 보수법으로 음수를 표현
- 2의 보수법은 +0 과 -0 혼돈에서 벗어나게 해주며 오늘날 대부분의 컴퓨터 시스템에서 음수를 표현하는 방식
- sbyte 형식 변수에 담긴 -1의 비트가 정말 1111 1111 인지 확인
using System;
namespace SignedUnsigned
{
class MainApp
{
static void Main(string[] args)
{
byte a = 255;
sbyte b = (sbyte)a;
Console.WriteLine(a);
Console.WriteLine(b);
}
}
}
5) 데이터가 넘쳐 흘러요
- 오버플로(Overflow)
using System;
namespace Overflow
{
class MainApp
{
static void Main(string[] args)
{
uint a = uint.MaxValue; // unit의 최대값. 4294967295
Console.WriteLine(a);
a = a + 1;
Console.WriteLine(a);
}
}
}
- 최저값 보다 작은 데이터를 저장 : 언더플로 (Underflow)
6) char
- 정수 계열 형식
3.4.2 부동 소수점 형식
- 소수점이 고정 되어 있지 않고 움직이면서 수를 표현한다. -> 더 제한된 비트를 이용해서 훨씬 넓은 범위의 값을 표현할수 있기 때문
- 부동 소수점형식은 정수 뿐만 아니라 유리수를 포함하는 실수 영역의 데이터를 다룬다.
- 단일 정밀도(Single Precision)
- 복수 정밀도(Double Precision)
- C#의 float 와 double 은 IEEE754 라는 표준 알고리즘에 기반한 데이터 형식
- IEEE754에 따르면 4바이트 크기의 float 형식은 수를 표현할때 1비트를 부호 전용으로, 가수부 23비트를 수를 표현하는데 사용, 나머지 지수부 8비트를 소수점의 위치를 나타내기위해 사용
- float 는 굉장히 넓은 범위의 수를 다루는데, float 형식이 가진 유효 숫자는 딱 7자리 빡에 없으니 7자리 이상의 수는 대략적으로 표현해야한다. -> '한정된 정밀도'
- float에 비해 두배의 메모리를 사용하는 double 형식을 복수정밀도를 가진 부동 소수점 형식
using System;
namespace FloatingPoint
{
class MainApp
{
static void Main(string[] args)
{
float a = 3.1415_9265_3589_7932_3846f; //float 형식 변수에 값을 직접 할당하려면 숫자 뒤에 f 를 붙여줘야 합니다.
Console.WriteLine(a);
double b = 3.1415_9265_3589_7932_3846;
Console.WriteLine(b);
}
}
}
- 정밀도 면에서 한계를 가지므로 float 보다는 double 사용을 권한다. 메모리가 2배로 사용하지만 그만큼 데이터 손실이 적기 때문
- decimal 형식 : double 보다 데이터 손실이 적은 형식
1) decimal
using System;
namespace Decimal
{
class MainApp
{
static void Main(string[] args)
{
float a = 3.1415_9265_3589_7932_3846_2643_3832_79f; // 숫자 뒤에 f를 붙이면 float 형으로 간주
double b = 3.1415_9265_3589_7932_3846_2643_3832_79; // 아무것도 없으면 double
decimal c = 3.1415_9265_3589_7932_3846_2643_3832_79m; // m 을 붙이면 decimal
Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);
}
}
}
- 회계 프로그램이나 계산기를 프로그래밍해야 한다면 float 나 double 보다는 decimal이 더 적합한 선택!
3.4.3 문자 형식과 문자열 형식
- char : 정수를 다루는 데이터형식 출신이지만 수가 아닌 '가','나','a','b','c' 와 같은 문자 데이터를 다룬다.
using System;
namespace Char
{
class MainApp
{
static void Main(string[] args)
{
char a = '안';
char b = '녕';
char c = '하';
char d = '세';
char e = '요';
Console.Write(a); // console.write() 메소드는 데이터를 출력한 후 줄을 바꾸지 않습니다.
Console.Write(b);
Console.Write(c);
Console.Write(d);
Console.Write(e);
Console.WriteLine();
}
}
}
- string 형식 : 여러개의 문자 형식을 하나의 실로 주르륵 묶어 처리
- string 은 정해진 크기나 담을수 있는 데이터 범위가 따로 정해져 있지 않다. 변수가 담는 텍스트의 양에 따라 그 크기가 달라지기 때문입니다.
namespace String
{
class MainApp
{
static void Main(string[] args)
{
string a = "안녕하세요?";
string b = "저는 ... 입니다...";
Console.WriteLine(a);
Console.WriteLine(b);
}
}
}
- 문자열 하나에 여러줄을 담으려면 이스케이프 문자(Escape sequence)를 이용
- \n : 줄바꿈(New Line) 을 나타내느 이스케이프 문자.
using System;
namespace Multiline
{
class MainApp
{
static void Main(string[] args)
{
string multiline = """
별 하나에 추억과
별 하나에 사랑과
별 하나에 쓸쓸함과
별 하나에 동경과
별 하나에 시와
별 하나에 어머니, 어머니
""";
Console.WriteLine(multiline);
}
}
}
3.4.4 논리 형식
using System;
namespace Bool
{
class MainApp
{
static void Main(string[] args)
{
bool a = true;
bool b = false;
Console.WriteLine(a);
Console.WriteLine(b);
}
}
}
3.4.5 object 형식
- object 는 물체, 객체 . 그러니 어떤 데이터 이든지 다룰수 있는 데이터 형식
- 상속 : 부모 데이터 형식의 유산을 자식이 물려받는 것, 부모로부터 데이터와 메소드를 물려받은 자식은 부모와 똑같이 동작할수 있다. 컴파일러는 자식을 부모로 간주 할 수 있게 된다!
- C#은 object 가 모든 데이터를 다룰수 있도록 모든 데이터 형식이 자동으로 object 형식으로 부터 상속 받게 했다.
- 컴파일러는 어떤 형식의 데이터라도 object 에 담아 처리할 수 있다!
using System;
namespace Object
{
class Program
{
static void Main(string[] args)
{
object a = 123;
object b = 3.141592745790784384934839m;
object c = true;
object d = "안녕하세용.";
Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);
Console.WriteLine(d);
}
}
}
- 이러한 메커니즘을 박싱과 언박식이라고 합니다!
3.4.6 박싱과 언박싱
- object 형식은 참조 형식이기 때문에 힙에 데이터를 할당
- int,double 형식은 값형식이기 때문에 스택에 데이터를 할당
- object형식에 값형식의 데이터를 힙에 할당하기 위한 '박싱'(Boxing) 기능
- object 형식에 값형식의 데이터를 할당하려는 시도가 이루어지면 object 형식은 박싱을 수행해서 해당 데이터를 힙에 할당합니다.
<박싱>
object a = 20;
- 20은 그림에서 처럼 박스에 담겨 힙에 할당되고, a 는 그 주소를 참조.
<언박싱>
object a = 20;
int b = (int)a;
- a : 20이 박싱되어 저장된 힙을 참조
- b : a가 참조하고 있는 메모리로 부터 값을 복사
- 박싱된 값을 꺼내 값 형식 변수에 저장하는 과정 = 언박싱
using System;
namespace BoxingUnboxing
{
internal class MainApp
{
static void Main(string[] args)
{
int a = 123;
object b = (object)a;
int c = (int)b;
Console.WriteLine(a);
Console.WriteLine(b); // a에 담긴 값을 박싱 해서 힙에 저장
Console.WriteLine(c); // b에 담긴 값을 언박싱해서 스택에 저장
double x = 3.1414213;
object y = x; // x에 담긴 값을 박싱해서 힙에 저장
double z = (double)y; // y에 담긴 값을 언박싱 해서 스택에 저장
Console.WriteLine(x);
Console.WriteLine(y);
Console.WriteLine(z);
}
}
}
3.4.7 데이터 형식 바꾸기
- 형식 변환(Type Conversion) : 변수를 다른 데이터 형식의 변수에 옮겨 담는 것
1) 크기가 서로 다른 정수 형식 사이의 변환
using System;
namespace IntegralConversion
{
class MainApp
{
static void Main(string[] args)
{
sbyte a = 127;
Console.WriteLine(a);
int b = (int)a;
Console.WriteLine(b);
int x = 128; // sbyte의 최대값 127보다 1 큰수
Console.WriteLine(x);
sbyte y = (sbyte)x; // 오버플로가 발생
Console.WriteLine(y);
}
}
}
2) 크기가 서로 다른 부동 소수점 형식 사이의 변환
- 부동 소수점 형식의 특성상 오버플로가 존재하지 않지만, 정밀성에 손상을 입는다.
using System;
namespace FloatConversion
{
internal class MainApp
{
static void Main(string[] args)
{
float a = 69.6875f;
Console.WriteLine("a : {0}", a);
double b = (double)a;
Console.WriteLine("b : {0}", b);
Console.WriteLine("69.6875== b :{0}", 69.6875 == b);
float x = 0.1f;
Console.WriteLine("x : {0}", x);
double y = (double)x;
Console.WriteLine("y: {0}", y);
Console.WriteLine("0.1 == y : {0}", 0.1 == y);
}
}
}
3) 부호 있는 정수 형식과 부호 없는 정수 형식 사이의 변환
using System;
namespace SingnedUnsignedConversion
{
class MainApp
{
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);
}
}
}
4) 부동 소수점 형식과 정수 형식 사이의 변환
- 부동 소수점 형식의 변수를 정수 형식으로 변환하면 데이터에서 소수점 아래 는 버리고 소수점 위의 값만 남긴다.
- 0.1 을 정수형식으로 변환하면 0 , 0.9 도 정수형식으로 변환하면 0
using System;
namespace FloatToIntegral
{
class MainApp
{
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);
}
}
}
5) 문자열을 숫자로, 숫자를 문자열로
- C# 은 정수 계열 형식, 부동 소수점 형식 모두에게 'Parse()' 라는 메소드 존재
int a = int.Parse("12345");
float b = float.Parse("123.45");
- 숫자 데이터 형식을 문자열로 바꾸는 방법: 정수 계열 데이터 형식이나 부동 소수점 데이터 형식은 자신이 가진 숫자를 문자열로 변환 하도록 object 로부터 물려받은 'ToString()' 메소드를 재정의했다.(오버라이드Override)
int c = 12345;
string d = c.ToString();
float e = 123.45;
string f = e.ToString();
using System;
using System.ComponentModel;
namespace StringNumberConversion
{
class MainApp
{
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 = Convert.ToInt32(e);
Console.WriteLine(f);
string g = "1.2345";
float h = float.Parse(g);
Console.WriteLine(h);
}
}
}