기본 문법
기본 자료형
개발자가 별도로 코드를 만들지 않아도 C# 언어에서 자체적으로 제공하는 데이터 형식.
정수형 기본 타입
이름 | 범위 | .NET Framework 형식 | 의미 |
---|---|---|---|
sbyte | -128~127 | System.SByte | 부호 있는 8비트 정수 |
long | –9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 | System.Int64 | 부호 있는 64비트 정수 |
ulong | 0 ~ 18,446,744,073,709,551,615 | System.UInt64 | 부호 없는 64비트 정수 |
실수형 기본 타입
이름 | 크기 | .NET Framework 형식 |
---|---|---|
float | 4바이트 | System.Single |
double | 8바이트 | System.Double |
decimal | 16바이트 | System.Decimal |
실수형 타입 선택 기준
소수점이 있는 연산을 할 때는 일반적으로 double을 사용한다. 하지만 빠른 처리 속도가 필요한 곳에서 연산하려는 값이 4바이트 실수로 충분하다면 float을 사용 할 수 있다.
decimal의 경우 반올림 오차가 허용되지 않는 회계 계산에 적합하다.
실수형 타입의 접미사
float f = 5.2f; //float의 경우에는 숫자 값 다음에 f.
double d = 10.5;
decimal money = 200.099m //decimal의 경우에는 숫자 값 다음에 m.
문자형 기본 타입
이름 | 범위 | .NET Framework 형식 | 의미 |
---|---|---|---|
char | U+0000 ~ U+FFFF | System.Char | 유니코드 16비트 문자 |
string | 문자열 | System.String | 유니코드 문자열 |
문자는 작은 따옴표를 사용해 표현한다.
char ch = 'A';
Console.WriteLine(ch); //A 문자 출력
char single quote = '\'' //작은 따옴표는 역슬래시 입력해야 표현가능.
char slash = '\\' //역슬래시는 두번입력해야 역슬래시로 표현.
기본 문법 요소
식별자
임의로 선택해서 이름지을 수 있는 단어.
변수
닷넷에서 변수의 종류는 값 형식, 참조 형식 이렇게 2가지 변수가 있다.
값 형식 & 참조 형식 변수
- 값 형식 : 값 자체가 스택 영역에 저장된다. 정수형, 실수형, 불린형 기본 타입 변수가 값 형식이다.
- 참조 형식 : 값은 힙 영역에 저장되고 그 값의 주소값이 스택 영역에 저장된다. 초기화되지 않은 모든 참조형 변수는 null 값을 가진다. string, 배열, 클래스, object
- 대입 : 값 형식끼리 대입했을 때는 스택 내부에서 각각 다른 위치에 동일한 값이 복사된다. 참조 형식의 경우에는 힙 메모리에 하나의 값만 위치한 상황에서 스택의 변수들이 같은 힙 위치를 가리킨다.
기본값
- bool : false
- 숫자 : 0
- 참조 형식 : null
상수
상수는 const 예약어를 쓰는데, 컴파일 할 때 값이 결정되어야 한다.
int n = Math.Max(0, 5); //프로그램을 실행할 때 n값이 결정
const int maxN = Math.Max(0, 5); //maxN은 상수이므로 컴파일할 때 값이 결정되어야 하는데
//Max 메소드는 런타임에 실행되므로 컴파일러가 어떤 값을 넣을지 몰라서 오류 발생
const int n = 5 * 100 / 2 //이런 단순 수식은 컴파일러가 계산해서 대입 가능 (상수식 이라고 함)
배열
배열도 참조 형식이기 때문에 배열의 값을 힙에 할당한다.
int [] products = new int[5]; //이런 식으로 선언.
int [] products = new int[5] {1,2,3,4,5}; //배열 개수 지정 초기화.
int [] products = new int[] {1,2,3,4,5}; //배열 개수 미지정.(컴파일러가 알아서 계산해서 크기 5로 지정)
string도 char의 배열이다.
관계 연산자, 논리 연산자
- 배타적 논리합(XOR) 연산자 : ^
- 단락 계산, 단축 평가 : 한 조건에 의해서 다른 조건의 결과값에 상관 없이 무조건 참, 거짓이 나오기 때문에 다른 조건은 실행도 되지 않는 것. (|| 일 때 한 쪽이 참, &&일 때 한 쪽이 거짓)
int n = 50;
int x = 100;
if (x > 10 || n++ > 10) // 단락 계산이 발생하기 때문에 n++부분이 실행되지 않아서 n값은 그대로 50에서 머무른다.
{
//생략
}
//증감 연산자는 논리 연산자의 피연산자에 해당하는 식에 쓰는 것 보다 따로 분리해서 쓰는 것이 바람직하다.
조건문
- switch 문에서 C/C++와 달리 case문에 break를 포함시키는게 강제사항이라서 break가 없으면 오류가 발생한다. case 문에 실행코드 없으면 생략 가능
반복문
- foreach 문 : foreach (표현식요소_자료형 변수명 in 표현식) 구문;
int [] arr = new int[] {1,2,3,4,5};
foreach (int elem in arr)
{
Console.WriteLine(elem); //1,2,3,4,5가 다섯줄에 걸쳐 출력된다.
}
//다음과 같이 var를 사용하면 다양한 타입에 대해서 foreach를 사용 가능하다.
foreach (var elem in arr)
{
//생략
}
문제풀이
for문을 이용한 별찍기
class StarTest
{
static void Main(string[] args)
{
int num;
Console.WriteLine("반복 횟수를 입력하세요.");
for (;;)
{
try
{
num = Convert.ToInt32(Console.ReadLine());
if (num <= 0)
{
Console.WriteLine("0보다 작거나 같은 수는 입력할 수 없습니다.");
}
else
{
for (int i = 0; i < num; i++)
{
for (int j = 0; j < i + 1; j++)
{
Console.Write("*");
}
Console.WriteLine();
}
break;
}
}
catch (FormatException)
{
Console.WriteLine("정수값을 입력해주세요.");
}
catch (OverflowException)
{
Console.WriteLine("int 범위의 값을 입력해주세요.");
}
Console.WriteLine("다시 입력해주세요.");
}
}
}
}
질문사항
유니코드와 인코딩 방식
유니코드란?
유니코드는 기존의 여러 문자 표현 방식들의 문제점을 해결하기 위해서 전 세계의 모든 문자를 컴퓨터로 표현할 수 있게 문자마다 고유의 Character code를 부여하는 방식이다. 그래서 기존에 발생하던 각 언어와 문자 체계에 따른 충돌 문제를 해결하였다. 유니코드를 사용하는 환경에서는 세계 각국의 언어를 깨뜨리지 않고 사용할 수 있다.
코드 포인트
코드 포인트는 유니코드에서 문자에 매겨진 번호를 의미한다. 표기 방식은 U+0000 으로 Unicode를 의미하는 U+와 코드포인트 값을 16진수로 적는다.
알파벳 'A'는 U+0041, 한글 '가'는 U+AC00 으로 표기한다.
유니코드의 구조
UCS(Universal Character Set)는 ISO 10646으로 정의된 문자 인코딩의 국제 표준이다. 유니코드는 UCS의 하위 집합이고, UCS의 구조를 알면 유니코드의 구조를 알 수 있다. 아래 그림은 UCS의 구조와 의미를 정리한 그림이다.
여기서 유니코드는 Group 00의 Plane 00 ~ 16을 사용한다. 총 17개의 Plane을 포함하므로 65536 x 17을 계산해보면 약 111만 개의 문자를 할당 가능한 것을 알 수 있다. 그리고 Plane 00의 영역을 BMP(기본 언어판) 이라고 지칭하는데, 주로 사용되는 문자들은 BMP 내에 있다.
유니코드는 2바이트 체계다. 하지만 계산을 해보면 17개의 Plane을 표현하는데 필요한 5 비트, Cell번호를 표현하는데 필요한 16비트를 합쳐 총 21비트가 유니코드의 모든 문자를 표현하기 위해서 필요하다는 것을 알 수 있다. (Group 표현은 Group 00만을 사용하므로 생략한다.)
유니코드와 한글
유니코드는 한글의 표현 방식을 완성형, 조합형 모두 지원한다. 완성형이란 완성된 글자 하나하나를 바로 쓸 수 있도록 번호를 부여하여 할당한 것이고, 조합형은 한글의 초성, 중성, 종성으로 쓰이는 자, 모음 단위로 할당하여 조합하여 쓸 수 있는 방식이다. 현대 한글 11,172자가 완성형 방식 처리에 쓰이고 있어서, 일상 생활의 거의 모든 단어를 표현할 수 있다. 조합형 방식은 자모음 하나 하나를 조합하기 때문에 용량이 더 크다는 문제 때문에 완성형에 없는 옛 한글을 표현하는 용도 이외에는 잘 쓰지 않는다.
유니코드의 인코딩
유니코드와 유니코드 인코딩을 가장 쉽게 설명하는 방법은 유니코드는 각 문자에 번호를 지정하는 방식을 말하면 인코딩은 유니코드 숫자를 표현하는 방법이라 보면 된다. 여러 인코딩 방식이 있지만 주로 사용하는 UTF-8, UTF-16, UTF-32에 대해서 설명한다.
-
UTF-32
UTF-32는 32비트로 표현하는 방식이다. 모든 코드 포인트를 32비트에 1:1로 매핑되고, 남는 11개의 앞 비트는 모두 0으로 채운다.
인코딩한 값 자체가 코드 포인트이기 때문에 해당 유니코드 문자를 찾기 쉽다. UTF-8 이나 UTF-16에 비해서 공간을 많이 차지하기 때문에 메모리 공간에 큰 제약이 없거나 고정 길이 인코딩이 필요할 때 쓰인다. 주로 Unix 환경에서 문자열을 메모리에서 다룰 때 사용된다.
* **UTF-16** UTF-16은 16비트로 표현하는 방식이다. BMP 영역 범위 내의 문자를 만나면 16비트로 1:1 매핑된다. 하지만 BMP 영역 범위(U+0000 ~ U+FFFF) 이외의 문자를 만나면 32비트로 표현하는 가변 길이 인코딩 방식이다. 주로 Java나 Microsoft 플랫폼에서 문자열을 다룰 때 사용된다.


BMP 영역을 벗어나는 문자를 인코딩 할 때에는 아래 그림과 같이 인코딩한다.

위의 변환 규칙에 따라서 변환을 하면, 인코딩 된 16비트 값이 0xD800 ~ 0xDFFF 사이의 값이 되도록 고안되었다. 변환된 값이 또 다른 문자로 잘못 인식되는 것을 막기 위해서 이 0xD800 ~ 0xDFFF 사이의 영역에는 문자가 할당되어 있지 않다. 이 영역을 Surrogate라 부르고 인코딩 된 상/하위 비트를 합쳐서 Surrogate Pair라고 부른다.
* **UTF-8** UTF-8은 8비트로 표현하는 방식이다. UTF-16은 주로 사용되는 BMP 영역 범위를 인코딩 하기에는 좋았지만, ASCII 문자도 2바이트로 변환하는 것이 문제였다. ASCII 문자는 1바이트여서 UTF-16으로 변환 시 "00 41 00 42" 처럼 문자열 중간에 00이 들어가게 된다. 이는 문자열 관련 C 함수들에서 00을 NULL로 인식하여 오류를 발생시킬 수 있다. 이런 문제를 피하기 위해서 UTF-8 이 제안되었다. UTF-8은 ASCII 호환성을 주 목적으로 하기 때문에 중간에 NULL이 들어가지 않도록 만들어졌다. ASCII 영역 (U+0000 ~ U+007F) 에 대해서는 1바이트로 1:1 매핑되고, 더 큰 코드 포인트에 대해서는 다음과 같이 인코딩된다.
|코드 포인트 범위|비트수|인코딩|
|-------------------|-------|--------|
|U+0000 ~ U+007F|7|그대로 인코딩|
|U+0080 ~ U+07FF|11|110xxxxx 10xxxxxx|
|U+0800 ~ U+FFFF|16|1110xxxx 10xxxxxx 10xxxxxx|
|U+10000 ~ U+1FFFFF|21|11110xxx 10xxxxxx 10xxxxxx 10xxxxxx|
위의 표에서 x로 표시된 부분에는 원래의 비트값을 순서대로 적는다.
그래서 ASCII 영역(U+0000 ~ U+007F) 내의 문자인 알파벳 같은 경우는 1바이트 인코딩, 한글 완성형은 AC00 ~ D7AF 영역에 매핑되어 있기때문에 UTF-8로 인코딩하면 3바이트로 인코딩이 된다. 주로 웹이나 DB에서 많이 사용된다.
* **BOM** 바이트 순서 표식(Byte Order Mark, BOM)은 유니코드에서 엔디안을 구별하기 위해 사용되는 문자로, 코드 포인트는 U+FEFF이다. (아랍어 표현꼴 마지막 문자로 할당되어 있다. 아랍어와의 특별한 상관관계는 없다.) 엔디안은 바이트를 배열하는 방법을 말하며, 큰 단위가 앞에 나오는 빅 엔디안과 작은 단위가 앞에 나오는 리틀 엔디안으로 나눌 수 있다.
 
UTF-8은 바이트 순서가 정해져있기 때문에 BOM 문자가 필요없지만, UTF-16, UTF-32 에서는 엔디안의 종류에 따라서 문자열의 값이 완전히 달라지므로, 문자열의 엔디안을 구별할 수 있는 표식이 필요하다. 이를 위해 유니코드 문자열 맨 앞에 BOM 문자를 붙여서 맨 처음에 읽히는 BOM 문자의 값에 따라서 엔디안을 구별한다. 인코딩에 따른 BOM 문자 값은 다음과 같다.
|인코딩 방식|BOM 문자 값|
|-------------|---------------|
|UTF-8|EF BB BF|
|UTF-16 빅 엔디안|FE FF|
|UTF-16 리틀 엔디안|FF FE|
|UTF-32 빅 엔디안|00 00 FE FF|
|UTF-32 리틀 엔디안|FF FE 00 00|
UTF-8의 경우 엔디안 문제가 일어나지 않으므로 BOM 문자를 붙일 필요가 없지만, 해당 자료가 UTF-8 인코딩이라는 것을 나타내기 위한 표식으로 사용하는 경우도 있다. 편집기에 따라서 UTF-8로 저장할 때 BOM 문자를 자동으로 추가하는데, 유닉스와 같은 UTF-8에서 BOM 문자를 사용하지 않는 경우에는 BOM 문자를 일반 문자로 잘못 인식하여 문제가 발생할 수 있다.
BOM 문자는 텍스트를 저장할 때 데이터 스트림의 맨 앞에 붙는다. (UTF-8은 편집 환경이나, 편집기 설정에 따라 붙이지 않을수도 있다.) 그리고 이 데이터를 자바로 불러와서 읽으면 BOM 문자가 포함되어 읽힌다. 이것으로 문자열을 읽을 때는 BOM 문자도 같이 읽히는 것을 알 수 있다.