형변환에 대하여
1. 형변환은 왜 일어날까 ?
상식적으로 우리는 2 + 1.625 = 3.625 라고 생각합니다.
그러나 0 과 1 밖에 모르는 컴퓨터 입장에서는 둘을 그냥 더한다면 예상치 못한 값이 나오게 됩니다.
보통 정수를 int 에 저장한다면 2 의보수법 ,
실수를 float 에 저장한다면 IEEE 754 표준의 부동소수점 변환을 이용합니다.
둘을 더한다면 11 이 나오게 됩니다.
우리의 상식과 생각보다 많이 멍청한 컴퓨터를 연결할 필요가 있는데
그 작업을 컴파일러 라는 프로그램이 형변환으로 담당해줍니다.
컴퓨터 입장에서는 자기가 멍청하다는 것을 들키지 않기 위해 형이 같은 경우만 연산합니다.
보통 형변환은 우리가 모르게 컴파일러가 암묵적으로 해주기 때문에 어떤 경우에 형변환이 일어나는 지
파악하는 것은 중요합니다.
2. 형변환이 일어나는 경우 (1) 보통의 산술 변환
보통의 산술 변환 ( Usual arithmetic conversions ) 은 산술 이나 비교를 포함한 대부분의 이항 연산자에서 정수형 또는 실수형인 두 피연산자에 대하여 적용됩니다.
규칙은 두 피연산자의 형에 따라 다른데 다음과 같습니다.
< 앞의 절차가 충족될 경우 뒤의 절차는 시행하지 않습니다. >
피연산자 A , B 가 있을 때
1) A , B 중 하나의 type 이 long double 일 경우 이에 맞춰 형변환 한다.
2) A , B 중 하나의 type 이 double 일 경우 이에 맞춰 형변환 한다.
3) A , B 중 하나의 type 이 float 일 경우 이에 맞춰 형변환 한다.
1 ~ 3 을 충족하지 않았다면 둘다 정수형 인게 확실한 상황입니다.
이때 위의 랭크 표에서 A , B 중 4 ~ 6 가 있을 경우 일단 3으로 정수의 승격 ( integer promotions ) 합니다.
4) A , B 의 type 이 같을 경우 형변환 하지 않습니다.
5) A , B 둘다 unsigned 이거나 둘다 signed 일 경우 낮은 랭크가 높은 랭크에 맞춰 형변환 합니다.
6) unsigned 의 랭크가 signed 의 랭크보다 높거나 같다면 signed 를 unsigned 에 맞춥니다.
7) signed 피연산자가 모든 unsigned 피연산자의 표현 범위를 포함한다면 unsigned 를 signed 에 맞춥니다.
8) 둘다 signed 의 랭크에 해당하는 unsigned 에 맞춥니다.
( 예를들어 (int , unsigned short int) 라면 , 랭크 3 의 unsigned int 에 맞춥니다. )
위의 복잡한 과정을 3줄 요약하면 다음과 같습니다.
1. 데이터의 손실을 최소화하기 위해 보통 정수형을 실수형에 맞춘다. ( float + int --> float + float )
2. 바이트의 손실을 최소화하기 위해 보통 작은 바이트를 큰 바이트에 맞춘다. ( long + int --> long + long )
3. unsigned 와 signed 사이의 연산은 웬만하면 하지 않는게 좋다.
3. 형변환이 일어나는 경우 (2) 할당 , 함수
다음의 경우에도 형변환이 일어납니다.
1. 할당 연산자에서 두 피연산자의 형이 일치하지 않음.
2. 함수에서 return 문과 return type 의 형이 일치하지 않음.
3. 함수 인자와 매개변수의 형이 일치하지 않음.
위의 경우
1 은 왼쪽 피연산자 , 2 는 return type , 3 은 함수 인자에 맞춰
1 의 오른쪽 피연산자 , 2 의 return 문 type , 3 의 함수 매개변수가 형변환 합니다.
#include <stdio.h>
int main( ){
int a = 0 ;
float b = 3.14 ;
a = b ; // a 에 3 이 할당
printf("%d" , a) ; // 3 출력
return 0 ;
}
이때 , 2 가지 문제가 발생할 수 있습니다.
첫째로 실수형을 정수형에 맞춰 형변환할 경우 소수부분이 손실될 수 있습니다.
위의 코드에서 a 에는 3 이 저장됩니다.
형변환에 의해 0.14 가 손실된 것입니다.
두번째로 변환하는 데이터가 변환받는 형의 범위를 벗어날 경우 의미 없는 값을 전달받을 수 있습니다.
#include <stdio.h>
int main( ) {
int a = -3;
unsigned int b = 0 ;
b = a ; // 의미없는 값 할당
printf("%u" , b) ; // -3 출력 하지 않음
return 0 ;
}
unsigned int 의 범위는 ( 0 ~ 4,294,967,295 ) 이기에 의미없는 값을 전달 받습니다.
4. 형변환 연산자 cast
컴파일러가 자동으로 형변환을 해주지만 때때로 형변환을 우리 스스로가 하고 싶을 때도 있습니다.
이를 위해 C 는 형변환 연산자를 제공합니다.
단항 연산자 이기에 모든 이항 연산자보다 우선순위가 높습니다.
보통 형변환 연산자는 3가지 경우를 위해 사용합니다.
첫째 , 형변환을 문서화하여 코드의 가독성을 높힘.
둘째 , 컴파일러를 거슬러 의도를 가지고 형변환
셋째 , overflow 예방
예시 코드 자리 (둘째 , 셋째 ~ )
5. pointer 와 array 사이에서 type decay(conversion)