C++/카루의 C++ 강좌

[카루의 C++ 강좌] 1-3. 변수의 선언과 자료형

카루-R 2020. 3. 20. 23:53
반응형

변수는 말 그대로 변할 수 있는 수입니다. 변수엔 자료형에 맞는 값을 저장하고 사용할 수 있습니다.

예를 들어,

int age;

라고 하면 age라는 이름의 int형, 즉 정수형 변수가 선언된 것입니다. int형 변수는 4바이트로, 저장할 수 있는 값의 범위는 -2,147,483,648~2,147,483,647입니다. 일반적으로 쓰기엔 이정도도 차고 넘치죠.

그럼 이 age란 변수에 나이를 저장해 보겠습니다.

int age;
age = 349;

네, age란 변수에 349를 할당했습니다. 변수에 값을 할당할 때는 대입연산자 '=' 를 사용하여 값을 대입할 수 있습니다. 수학에서의 등호랑은 좀 달라요. 변수명이 반드시 왼쪽에 와야 합니다. 349 = age; 이렇게 하면 작동하지 않습니다.

변수의 이름은 필요에 따라 지으면 됩니다. 예를 들어 사과의 수를 저장하는 변수라면 apple, 연도를 저장한다면 year 등과 같이 직관적이고, 다루기 쉬운 이름을 변수명으로 하는 게 좋습니다.

그런데 변수명에는 일단 규칙이 있습니다.

변수명 선언 규칙

  1. 원칙적으로는 영문 대소문자 및 숫자, 언더바(_)만 사용 가능합니다. 그러나 예외적으로 컴파일러에 따라 한글이 지원되는 경우도 있습니다.

  2. 변수명은 숫자로 시작할 수 없습니다.

  3. 변수명은 대소문자를 구분합니다.

  4. 이미 있는 변수나 함수, C++의 예약어를 변수명으로 사용할 수 없습니다.

    이 네 가지만 기억하시면 됩니다. 길이 제한도 있긴 한데, 워낙 커서 그 길이까지 쓰는 경우는 단 한 번도 없었습니다. 뭐 너무 길면 컴파일러가 알려주겠죠. 중요한 건 위의 네 가지 입니다. 꼭 숙지하시기 바랍니다.

// 올바르게 지어진 변수명
int age;
int people;
int GGHS10;
int Goyang_Global_High_School;

// 잘못된 변수명
int age;             // 위에 이미 age가 있습니다
int pri#ce;          // 언더바를 제외한 특수문자는 사용 불가능합니다.
int var iab le;      // 변수명에 띄어쓰기가 있으면 안 됩니다.
int 2020year;        // 숫자로 시작하면 안 됩니다.
int cout;            // 이건 일단은 가능합니다. 자세한 건 '4-5. 네임스페이스' 참고.

자료형

자료형은 데이터형이라고도 하며, 무엇을 담느냐에 따라 자료형도 다른 것을 선택해야 합니다. 크게 정수, 실수, 문자, bool 자료형으로 볼 수 있습니다.

  자료형(데이터형) 대표 이름(타입) 메모리 크기 값의 범위
 

short

short int

signed short int

short int 2바이트

-32,768

~32,767

unsigned short

unsigned short int

unsigned short int 0~65,535

int

signed

signed int

int 4바이트 -2,147,483,648~2,147,483,647

unsigned

unsigned int

unsigned int

0~

4,294,967,295

long

long int

signed long

signed long int

long int

(x32) 4바이트

(x64) 8바이트

(x32) -2,147,483,648

~2,147,483,647

(x64)

–9,223,372,036,

854,775,808~

9,223,372,036,

854,775,807

unsigned long

unsigned long int

unsigned long int

(x32) 0~

4,294,967,295

(x64) 0~18,446,744,073,709,551,615

long long

long long int

signed long long

signed long long int

long long int 8바이트

–9,223,372,036,

854,775,808~

9,223,372,036,

854,775,807

unsigned long long

unsigned long long int

unsigned long long int 0~18,446,744,073,709,551,615

실수 계열

float

고정소수점

4바이트

3.4E-38 ~ 3.4E+38

double

부동소수점

8바이트

1.79E-308~

1.79E+308

long double

 

16바이트

(컴파일러마다 다름)

문자 계열

signed char

unsigned char

1바이트

부호 있는 문자

부호 없는 문자

char

문자 한 글자

char8_t

1바이트

UTF-8 문자

char16_t

2바이트

UTF-16 문자

char32_t

4바이트

UTF-32 문자

wchar_t

윈도우: 2바이트, 나머지: 4바이트

유니코드 문자

와..이렇게 보니까 정말 많네요. 다만 이 표를 모두 외우실 필요는 없습니다. 저도 다 알진 못해요. 그 중에서 가장 많이 쓰이는 자료형에 파란색 강조를 해 두었으니, 참고하세요.

그리고, signed는 생략이 가능합니다. 또한 short나 long 뒤에 붙는 int도 생략이 가능합니다.

자, 다양한 변수를 선언하고 값을 대입해볼까요?

int num = 10; // 선언을 하면서 동시에 값을 대입했습니다.
short s1, s2, s3; // 자료형이 같으면 쉼표로 한번에 여러 변수를 선언할 수 있어요.

char ch;
ch = 'A'; // 문자를 대입할 때는 작은 따옴표로 묶어줍니다.

double pi = 3.1415926535;
long long ll = 1000000000000000LL; // int형의 범위를 넘는 아주 큰 수일 경우 LL을 붙입니다.

참고로, 자료형이 저렇게 많긴 하지만 CPU에 최적화 된 자료형은 int이기 때문에 short 등은 잘 쓰이지 않습니다. 일반적으로 정수는 int를, 아주 큰 정수는 long long을, 실수는 double을 많이 사용합니다. C++ 입문자들께서도 UTF를 다룰 일이 없기 때문에 문자는 보통 char을 가장 많이 사용합니다.

변수는 사용하기 전에 반드시 초기화를 해야 합니다. 변수에 처음으로 값을 대입하는 걸 초기화라고 하는데, 초기화를 안 하면 문제가 생깁니다.

변수는 컴퓨터의 RAM, 즉 메모리 어딘가에 할당이 되는데 (만들어지는데) 이때 메모리 안에 들어있던 값을 가집니다. 다시 말해서 아무값이나 들어있다는 겁니다.

int sum;
sum = sum + 55;

즉, 이렇게 하면 무슨 값을 얻을 지 모른다는 뜻입니다. 따라서 변수를 사용하기 전에 초기화를 (일반적으로 정수형 변수는 0으로 초기화합니다) 해야 합니다. 초기화란 변수에 처음 값을 대입하는(넣는) 행위를 뜻합니다.

int sum = 0;

이렇게 하는 건 기존 C언어식 초기화 입니다. C++에서는 다른 방식의 초기화를 지원합니다.

int sum(0); /* 또는 */ int sum{0};

이렇게 함수를 호출하듯 초기화를 할 수 있습니다. 아직 함수에 대해 배우진 않았지만, C++에서는가급적 저렇게 "중괄호"를 이용해 초기화를 하시기 바랍니다. 이유는 나중에 설명하겠습니다.

앞으로 모든 예제 코드에선 중괄호 초기화를 사용하겠습니다.

특수한 자료형

논리형

bool

1바이트

true, false

자동

auto

 

초기화한 자료형의 값

decltype( )

자, 엄청나게 중요한 자료형들입니다. 자료형 때문에 머리가 아팠을 분들을 위해 준비해보았습니다. 나머지 자료형들은 위의 예제만 잠깐 봐도 어떤 자료형인지 짐작하시겠지만, 이 셋은 유추하기 어려우니 따로 설명해 드리겠습니다.

 

Boolean

흔히 bool 타입이라고 부르고, C++에서도 bool 키워드를 사용합니다. 참과 거짓을 표현하는 자료형입니다. 보통 C계열 언어에서는 0은 거짓이고 나머지 수는 모두 참을 나타내는데, 이렇게 숫자로 표현하면 가끔 오류가 생길 수 있어서 C++에서는 아예 true, false 키워드를 만들었습니다.

아래와 같이 사용합니다.

bool result{true};
result = false;

 bool 타입의 변수에는 숫자를 넣으면 안 되고 반드시 true와 false라는 키워드만 대입할 수 있습니다. 이 bool 타입은 후에 배울 if문에서 진가를 발휘합니다.

 

auto (C++11)

 C++11에서 auto라는 키워드의 기능이 바뀌었습니다. 기존의 auto 키워드는 거의 기능이 없다시피 (사실상 아무도 안 쓰는)한 예약어였는데, 이제는 초기값의 자료형에 맞춰 변수의 형식을 자동으로 결정해주는 역할을 합니다.

직접 보시죠.

#include <iostream>

int main()
{
    auto year{2020};                   // int형으로 자동 추론
    auto pi{3.141592};                 // double형으로 자동 추론
    auto ch{'a'};                      // char형으로 자동 추론
    long long bigInt{3423423};         
    auto bigInt2{bigInt};              // long long형으로 자동 추론

    std::cout << "year: "    << year    << std::endl;
    std::cout << "pi: "      << pi      << std::endl;
    std::cout << "ch: "      << ch      << std::endl;
    std::cout << "bigInt2: " << bigInt2 << std::endl;
}

출력 결과

year: 2020
pi: 3.14159
ch: a
bigInt2: 3423423

 보시다시피 초기값에 맞춰서 자동으로 형식을 결정하고, 초기화를 하는 걸 알 수 있습니다. 그 대신 선언할 때 초기화를 동시에 해 줘야 합니다. 저렇게 숫자를 넣어도 되고, 이미 있는 변수를 넣어도 괜찮습니다.

여담으로 위의 std::cout 문장은 한 문장으로 묶을 수 있습니다.

std::cout << "year: " << year << std::endl
    << "pi: " << pi << std::endl
    << "ch: " << ch << std::endl
    << "bigInt2: " << bigInt2 << std::endl;

세미콜론으로 문장을 끝내지만 않는다면 << 을 통해 몇 번이든 무언가를 출력할 수 있습니다. 다만 맨 앞에 std::cout가 와야 한다는 것만 기억하세요.

사실 auto의 진가는 자료형이 아주 길 때, 혹은 함수의 반환값으로 초기화를 하는 경우입니다.

std::chrono::time_point<std::chrono::system_clock> tp = std::chrono::system_clock::now();

위의 문장은 auto를 사용하여 아래와 같이 간단하게 나타낼 수 있습니다.

auto tp = std::chrono::system_clock::now();

 함수가 워낙 길어서 중괄호 초기화 대신 대입연산자를 사용했습니다. 아무튼 이렇게 긴 타입을 간단하게 사용할 수 있다는 장점이 있습니다. 때에 따라선 auto를 사용하는 게 가독성이 더 좋아질 때도 있습니다.

그리고, 지금 문자열을 저장하고 싶다면 auto를 사용해 보세요. 문자열은 여러개의 문자를 포함하고 있고, "큰따옴표를 이용하여 나타냅니다. std::cout 로 출력할 수 있습니다.

auto string = "This is a string.";
std::cout << string << std::endl;

 

 

decltype

 auto가 초기값에 맞추어 자동으로 형식을 결정했다면 decltype은 '~와 같은 자료형' 을 정해주는 것에 가깝습니다.

decltype(x) 라고 하면 x와 같은 자료형이 됩니다. 이때 x는 10, 3.14, 'A'와 같은 상수가 되어도 좋고, 이미 선언된 변수가 되어도 좋습니다.

int a; char b; double c;

decltype(10)   int1;
decltype(a)    int2;
    
decltype('c')  char1;
decltype(b)    char2;

decltype(3.14) double1;
decltype(c)    double2;

 자료형을 초기값으로 추론하는 게 아니라 ()안의 값으로 결정하기 때문에 따로 초기화를 하지 않아도 오류는 없습니다. 다만 거듭 얘기했듯 변수를 선언하면 동시에 초기화를 하는 습관을 들이는 게 좋습니다. decltype은 위처럼 상수 또는 변수로 타입 결정이 가능합니다.

 

decltype(auto)라고 하면 어떤 일이 발생할까요?

"[C++ 심화] 2. decltype(auto)에 관하여"를 참고해 주세요.

 

상수 리터럴

소스코드에 그냥 10이라고 적으면 이는 int형 상수로 간주합니다. 이때 리터럴이라 하면 10, 'A'와 같이 변수에 저장되지 않은 날(raw) 값을 말합니다.

또는 숫자와 문자의 앞뒤로 알파벳을 적어줘야 하는 경우가 있는데, 각 자료형에 맞는 리터럴은 다음과 같습니다.

// 정수형. 리터럴이 숫자 뒤에 붙고, 대소문자 구분이 없음
short s = 3;               // short는 자신만의 리터럴이 없습니다.
unsigned short us = 3U;    // unsigned의 리터럴 U만 사용
int n = 5;                 // 정수는 아무 표시가 없으면 int로 간주합니다.
unsigned int un = 5U;      // unsigned의 리터럴 U
long l = 7L;               // long은 리터럴 L을 사용
unsigned long ul = 7UL;    // unsigned의 U, long의 L
long long ll = 10LL;       // long long의 리터럴 LL을 사용
unsigned long long ull{10ULL}// unsigned의 U, long long의 리터럴 LL

// 실수형, E 또는 F를 사용하며, 소문자로 표기해도 무방
float f1 = 3.14F            // float의 리터럴 연산자 .(소수점) + F
double d1 = 6.28            // 소수점만 쓰면 double
double d2 = 0.6E-28;        // 이런 표기도 가능
float f2 = 0.3E-14F;        // F가 붙으면 float
auto what = 100.;           // 숫자 뒤에 소수점이 있으니 int가 아닌 double로 처리

// 문자형. 대소문자를 구분합니다.
char ch = 'A';              // 작은따옴표만 쓰면 char형
char8_t ch8 = u8'A';        // C++20에 추가된 u8을 앞에 쓰면 UTF-8
char16_t ch16 = u'A';       // 소문자 u를 쓰면 UTF-16
char32_t ch32 = U'A';       // 대문자 U를 쓰면 UTF-32
wchar_t wch = L'A';         // 대문자 L을 쓰면 wchar_t

// 기타
bool b = true;              // bool은 true와 false만 저장할 수 있습니다.
auto str = "String.";       // 문자열 저장
auto u8str = u8"String.";   // UTF-8 문자열 저장
auto u16str = u"String.";   // UTF-16
auto u32str = U"String.";   // UTF-32
auto wstr = L"String.";     // 유니코드
auto rstr = R"(String.)";   // 날 문자열 리터럴

 이 정도만 알아두시면 됩니다. 사실 저걸 모두 사용하진 않아요. 자주 사용하는 char, int, double 위주로 기억하시고 나머지는 필요할 때마다 봐도 괜찮습니다. 그리고 프로그래밍을 하다보면 하나씩 기억에 남을 거예요.

정수는 2진수, 8진수, 16진수로도 표현이 가능한데 이건 "2-1. 변수와 상수, 배열 I"에서 다루겠습니다.

 

1-3. 도전 과제

  1. short형 변수를 30으로 초기화하고 출력해 보세요.
  2. 제곱근 2는 약 1.414213입니다. 이 값을 long double에 저장하고 출력해 보세요.
  3. auto를 활용하여 문자열 Effective C++을 저장하고, 출력해보세요. 문자열을 표현하려면 "큰따옴표"로 묶어줘야 합니다.
auto num = 250.;

4. 위 코드에서 변수 num은 어떤 타입입니까?

auto su = '3';

5. 위 su의 자료형은 무엇입니까?


 조금 복잡하죠? 괜찮아요. 처음부터 잘 할수 있는 사람은 없습니다.

차근차근 하나씩 익혀가도록 해요. 지금은 가볍게 넘어가고, 나중에 다시 볼 일이 있으면 그때 다시 돌아오셔도 괜찮습니다.

참고: 본 강좌의 연계 심화 강좌는

"[C++ 심화] 2. decltype(auto)에 관하여"입니다.

반응형