소년코딩

05.01 - 암시적 형 변환 (Implicit type conversion)

이전에 변수의 값이 일련의 비트로 저장되는 것과 변수의 자료형은 컴파일러에 비트를 의미 있는 값으로 해석하는 방법을 알려준다는 것을 배웠다. 다른 자료형은 "같은" 숫자를 다르게 나타낼 수 있다. 예를 들어, int 값 3과 float 값 3.0은 완전히 다른 이진수 패턴으로 저장된다.

float f = 3; // initialize floating point variable with integer 3

위의 경우 컴파일러는 값 3을 나타내는 비트만 float f로 할당할 수 없다. 대신 정수 3을 부동 소수점 숫자로 변화해야 하며, 이 값을 할당할 수 있다.

한 자료형에서 다른 자료형으로 값을 변환하는 것을 형 변환이라고 한다. 형 변환은 여러 가지 경우에 발생할 수 있다.

- 다른 자료형 값으로 변수 초기화 또는 할당하는 경우:
double d(3); // initialize double variable with integer value 3
d = 6;       // assign double variable with integer value 6
- 함수 매개 변수에 다른 자료형의 값을 전달하는 경우:
void doSomething(long l)
{
}

doSomething(3); // pass integer value 3 to a function expecting a long parameter
- 함수에서 다른 자료형의 값을 반환하는 경우:
float doSomething()
{
    return 3.0; // Return double value 3.0 back to caller through float return type
}
- 다른 자료형의 피연산자가 있는 이항 산술 연산자를 사용하는 경우:
double division = 4.0 / 3; // division with a double and an integer

이러한 모든 경우, C++은 데이터를 한 자료형에서 다른 자료형으로 변환하기 위해 형 변환을 한다.

기본적인 형 변환에는 두 가지 유형이 있다.

  • 암시적 형 변환(implict type conversion): 즉 컴파일러가 자동으로 하나의 기본 자료형을 다른 자료형으로 변환한다. 자동 형 변환(automatic type conversion)이라고 불린다.
  • 명시적 형 변환(explict type conversion): 형 변환을 하기 위해 형 변환 연산자(type casting operator)를 사용한다.

이 포스트에서는 우선 암시적 형 변환을 다루고, 다음 포스트에서 명시적 형 변환을 다룰 예정이다.


암시적 형 변환

암시적 형 변환은 한 기본 자료형이 예상되지만 다른 기본 자료형이 제공될 때마다 수행되며, 변환을 수행하는 방법을 컴파일러에 명시적으로 알려 주지 않는다. 위에서 언급한 경우들은 모두 암시적 형 변환이다.

- 숫자 승격 (numeric promotion)

한 자료형의 값이 더 큰 유사한 자료형의 값으로 변환하는 경우 "숫자 승격(numeric promotion)"이 일어난다. 예를 들어, intfloat으로 floatdouble로 승격될 수 있다.

long   l(64);    // promote the integer 64 into a long
double d(0.12f); // promote the float 0.12 into a double

숫자 승격은 항상 안전하며 데이터 손실이 발생하지 않는다.

- 숫자 변환 (numeric conversion)

큰 자료형의 값이 더 작은 유사한 자료형의 값으로 변환하거나 서로 다른 자료형 간에 변환하는 경우 "숫자 변환(numeric conversion)"이 일어난다.

double d = 3; // convert integer 3 to a double (between different types)
short s  = 2; // convert integer 2 to a short  (from larger to smaller type)

항상 안전한 "숫자 승격"과는 다르게 숫자 변환으로 인해 데이터가 손실되거나 그러지 않을 수도 있다. 이 때문에 숫자 변환이 일어나는 모든 암시적 형 변환의 코드는 컴파일러에 경고를 보낸다. 다음과 같은 경우들을 주의해야 한다.

1. 범위가 충분히 크지 않은 자료형으로 변환하면 예기치 않는 결과가 발생한다.
int main()
{
    int i = 30000;
    char c = i;

    std::cout << static_cast<int>(c);

    return 0;
}

// 48

위 코드에서 정수 30000을 char 자료형(범위: -128 ~ 127)에 할당했다. 이렇게 하면 오버플로가 발생해 원치 않는 결과가 출력된다.

2. 부동 소수점 숫자에서 정수로 변환하는 것은 분수 값을 모두 손실시킨다.
int i = 3.5;
std::cout << i;

// 3 : the fractional value (.5) is lost

산술 표현식 평가하기 (Evaluating arithmetic expressions)

표현식을 평가할 때, 컴파일러는 각 표현식을 개별 하위 표현식으로 나눈다. 산술 연산자의 피연산자는 모두 같은 자료형이어야 하므로 컴파일러는 다음과 같은 규칙을 사용한다.

  • 피연산자의 자료형이 int보다 작은 정수인 경우, int또는 unsigned int로 승격된다.
  • 피연산자의 자료형이 여전히 같지 않으면, 컴파일러는 가장 높은 우선순위 피연산자를 찾고 다른 피연산자를 암시적 형 변환을 통해 일치시킨다.

피연산자의 우선순위는 다음과 같다.:

  • long double (highest)
  • double
  • float
  • unsigned long long
  • long long
  • unsigned long
  • long
  • unsigned int
  • int (lowest)
예제 1
#include <iostream>
#include <typeinfo> // for typeid()

int main()
{
    short a(4);
    short b(5);
    std::cout << typeid(a + b).name() << " : " << a + b << std::endl; // show us the type of a + b

    return 0;
}

// int : 9

short는 정수이기 때문에, 더하기(+)가 수행되기 전에 int로 승격된다. 두 개의 int를 더한 결과는 int다.

예제 2
#include <iostream>
#include <typeinfo> // for typeid()

int main()
{
    double d(4.0);
    short s(2);
    std::cout << typeid(d + s).name() << " : " << d + s << std::endl; // show us the type of d + s

    return 0;
}

// double : 6.0

shortint로 승격된다. 그러나 두 피연산자는 여전히 일치하지 않기 때문에 int보다 우선순위가 더 높은 double로 승격된다. 두 개의 double을 더한 결과는 double이다.

예제 3

문제를 일으킬 수 있다.

std::cout << 5u - 10; // 5u means treat 5 as an unsigned integer

// 4294967291

이같은 경우 우선순위에 의해서 부호없는 정수(unsigned int)로 승격되고 결과값의 오버플로로 인해 예상치 못한 결과를 얻을 수도 있다.

위 예제는 부호 없는 정수를 피하는 많은 이유 중 하나다.


cpp 번역: 이 포스트의 원문은 http://www.learncpp.com/cpp-tutorial/44-implicit-type-conversion-coercion/ 입니다.

'C++ 이야기 > 05. 다양한 타입' 카테고리의 다른 글

C++ 05.06 - typedef  (1) 2018.07.04
C++ 05.05 - enum class  (1) 2018.07.04
C++ 05.04 - 열거형, enum  (3) 2018.07.03
C++ 05.03 - 문자열, std::string  (1) 2018.07.03
C++ 05.02 - 명시적 형 변환 (Explict type conversion)  (0) 2018.07.02
댓글 로드 중…

블로그 정보

소년코딩 - 소년코딩

소년코딩, 자바스크립트, C++, 물리, 게임 코딩 이야기

최근에 게시된 이야기