[C++] 변수 타입 : 문자와 문자열

👻 문자(char)

이전 시간에 참/거짓을 나타내는 bool에 대해 배웠다. 불리언도 어떻게보면 1바이트의 숫자를 나타내는 정수와 같은 변수 타입이라고 했지만, 참/거짓을 나타낼 때 1과 0보다는 true/false가 한 눈에 알아보기 더 쉽기 때문에 따로 타입을 나눠서 사용한다고 했다. 문자도 마찬가지이다. 1바이트의 값을 나타내는 문자 타입은, 마찬가지로 그냥 정수 지만 ‘문자’ 의미를 나타내기 위해 따로 분리되어 사용된다.

char : 알파벳 / 숫자 문자를 나타낸다.
wchar_t : 유니코드 문자를 나타낸다.

char ch = 97;

우선 char 타입으로 변수를 하나 선언해보자. 97이라는 값을 대입했지만 막상 실행시켜보면 a라는 값이 나온다. 👉 아스키코드 떄문
그냥 숫자를 입력하면 그 아스키코드에 해당하는 문자가 출력되므로, 문자 자체를 출력하고 싶다면 작은 따옴표(‘’)로 값을 묶어 선언해야한다.

char ch = 'a';
char ch2 = '1';
char ch3 = 'a' + 1; // 결과값은 문자 'a'의 다음 주소값에 있는 'b'이다.

ch2의 경우, ‘1’이라는 문자값 대신, 문자 1을 뜻하는 아스키코드 값이 들어가기 때문에 ch3처럼 문자와 정수의 덧셈도 가능하다.


🌱 유니코드(Unicode)

요즘같은 국제화 시대에는 영어만으로 서비스 하기가 쉽지 않다.
전 세계 모든 문자에 대해 유일한 코드를 부여해야 모든 문자를 사용할 수 있는데 이를 유니코드(Unicode)라고 한다.

💡
유니코드에서 가장 많은 번호를 차지하는 언어가 한국어, 중국어 등이 있다.
(뚥, 뷁, 얂 같은 글자도 다 고유코드가 있기 때문에 양이 많다.)

유니코드는 여러가지 표기 방식이 있지만, 그 중 대표적으로 UTF8UTF16이 있다.

  • UTF8
    • 알파벳, 숫자는 1바이트이다. (ASCII와 동일한 번호를 가진다.)
    • 유럽 지역의 문자는 2바이트이다.
    • 한글, 한자 등은 3바이트이다.
  • UTF16
    • 알파벳, 숫자, 한글, 한자 등 거의 대부분의 문자는 2바이트이다.
    • 매우 예외적인 고대 문자는 4바이트이다. (사실상 무시해도 상관없다.)

왜 표기방식이 나뉘었을까?
👉 서로 장단점이 크로스된다.
알파벳과 숫자만 사용할거면 용량이 적은 UTF8을 사용해도 되지만, 한글의 사용을 예로 들어보면 그 차이를 쉽게 알 수 있다. 한글을 사용할 경우, UTF8은 3바이트로 크기가 커지게 되지만 UTF16은 2바이트로 고정되어 길이 예측이 쉬워 용량 관리에 편하다는 점이 있다.


🪐 유니코드 문자(wchar_t)

wchar_t wch = L'안';

문자를 표기하는 방식 중에 유니코드 문자를 표기하는 wchar_t에 대해서 간단히 알아보자. 해당 타입은 UTF16인 문자를 나타내기 위해 사용하는 변수 타입니다. 유니코드 문자라는 걸 확실히 알 게 하기위해 작은 따옴표로 감싼 문자 앞에 알파벳 L을 붙인다.

위의 코드를 입력한 후, main 함수 안에 cout << wch << endl; 코드를 입력하고 출력해보자.
결과값은 이 아닌, 50504가 나오게 된다.

50504가 나오는 이유?
출력을 나타내는 coutchar 전용이기 때문이다. coutwcout으로 바꿔주면 유니코드 문자를 출력할 수 있는데, 한국어는 인식이 불가하므로 해당 코드 이전에 wcout.imbud(local("kor")); 코드를 추가해줘야 결과가 제대로 출력된다.

wchar_t wch = L'안';

int main()
{
    wcout.imbue(locale("kor"));
    wcout << wch << endl;
}

💡 각 코드에 대응하는 문자만 생각해서 입력해줘도 된다.

//'안' 👉 숫자 표현으로도 가능
wchar_t wch = 0xc548;   // L'안';

👻 Excape Sequence

표기하기 애매한 문자를 표현할 때 사용한다.

\t = 아스키코드 9 = Tab
\n = 아스키코드 10 = LineFeed(한 줄 아래로)
\r = 아스키코드 13 = CarriageReturn(커서 «)

출력하고자 하는 문자 앞에 백슬래시(\)를 넣어 코드로 인식되는 것을 방지해준다.


👻 문자열

문자열문자들이 열을 지어서 모여 있는 것 을 뜻한다.
정수는 고정 길이(1~8바이트)로 데이터를 저장하지만 문자열은 가변 길이를 가진다. 문자열 끝에는 항상 \00(null)이 들어가있다.

char str[] = { 'h', 'e', 'l', 'l', 'o' };
char str2[] = "Hello World";

해당 문자열 선언을 main 함수 밖(section .data)에 저장되게끔 선언하면 출력을 해도 값이 잘 나오는 것을 확인할 수 있지만, 스택 메모리에 저장하기 위해 main 함수 안에서 선언을 하게 되면 해당 문자열 뒤에 이상한 값이 함께 출력되는 것을 확인할 수 있다.

💡
data 영역은 대부분 0으로 초기화 되어있기 때문에 0을 만나 바로 문자열이 끝나 제대로 출력되지만, 스택은 초기화되어있지 않아 0을 만날 때까지 값을 출력하기 때문이다. 그래서 스택 안에 값을 입력할 땐 문자열 마지막에 \0을 반드시 추가해줘야 정상적으로 작동된다.

char str[] = { 'h', 'e', 'l', 'l', 'o', '\0' }

💡
char str2[] = "Hello World";의 경우, 해당 코드에 마우스를 오버시키면 문자열의 길이가 12로 뜨게 된다. 마지막에 0값까지 추가가 되어있기 때문이다.
고로 위의 직접 배열 방식보다 큰 따옴표(“”)로 묶은 아래 방식이 더 안전하다고 볼 수 있다.


👻 글을 마치며

이번 시간에는 문자와 문자열에 대해 배웠다. 신기했던 게 data 영역에서는 이미 0으로 초기화되어있어 문자열이 잘 출력되지만, 스택 메모리는 이상한 값이 들어간다는 것이었다. 이렇게 여기저기서 변수를 선언하고, 테스트해보며 각각 어느 부분을 맡고있는지 코드를 세세하게 살펴볼 수 있어서 유익한 시간이었던 것 같다. 이전에 배웠던 어셈블리어랑 비교해가면서 공부하니 지식에 대한 깊이도 두배로 늘어나는 기분이 들었다. 또한 utf8, utf16 등의 문자를 접한 적은 많았지만 자세한 의미까지는 몰랐었는데, 이번 시간에 대략적으로 큰 틀을 잡을 수 있어서 좋았다. 얼른 실제 프로젝트를 만들어보면서 공부했던 이론들을 적용시켜보고 싶어졌다. ☺


소스코드 보러가기


출처
인프런 Rookies님 강의

Categories:

Updated:

Leave a comment