[왕초보 임베디드-C 공부 일기] 12. 형변환과 캐스팅

C언어에서 형변환(Type Conversion)과 캐스팅(Casting)은 모두 데이터의 크기와 형태, 즉 자료형을 조작하는 것을 일컫는 개념이다. 이 두 개념은 혼용되어 쓰이기도 하지만, 엄밀히 말하면 컴파일러가 자동으로 수행하느냐, 개발자가 강제로 수행하느냐의 차이가 있다. ----------------------------------------------

1. 암시적 형변환 (Implicit Type Conversion / 자동 형변환)

정의

연산을 수행할 때 데이터 손실을 막기 위해, 컴파일러가 스스로 판단하여 데이터의 크기가 더 '큰 쪽' 혹은 표현 범위가 더 '넓은 쪽(예 : 정수 -> 실수)' 으로 자료형을 자동으로 맞추는 현상이다. 작은 컵(int8_t)에 담긴 데이터를 큰 컵(int32_t)으로 옮길 때는 데이터가 넘칠 위험이 전혀 없다. 그래서 컴파일러가 개발자에게 확인 절차 없이 안전하게 옮겨 담는다.

사용 예시 : 정수와 실수 함께 계산

가장 흔한 사례는 정수와 실수를 함께 계산할 때 발생한다. 데이터가 유실되지 않도록 더 '큰' 혹은 '넓은' 표현 방식을 가진 쪽으로 컴파일러가 조용히 형태를 맞춘다.
#include 

int main() {
	int count = 10;        //정수형
	float weight = 2.5f;   //실수형
	
	// 정수와 실수를 곱하는 상황
	float toal_weight = count * weight;
	printf("총 무게 : %f\n", total_weight); //25.000000 출력
	return 0;
}
count * weight를 계산할 때, 컴퓨터는 정수(10)와 실수(2.5)를 그대로 곱할 수 없다. 이때 컴파일러가 개입해서 정수 10을 실수 10.0f로 몰래(암시적으로) 바꾼 뒤에 곱셈을 수행한다. 데이터의 손실이 없기 때문에 안전한 변환이다. --------------

2. 명시적 형변환 (Explicit Casting / 강제 형변환)

정의

프로그래머가 변수 앞에 원하는 자료형을 명시하여, 컴파일러의 자동 변환 규칙을 무시하고 강제로 데이터의 크기나 해석 방식을 바꾸는 문법이다. 데이터 손실이 발생할 수 있지만, "내가 잃어버리는 데이터를 감수하고서라도 이 규격에 맞추겠다."라고 개발자가 하드웨어에 설정하는 것이다.

사용 예시 : 정수 나눗셈

프로그래머가 변수 앞에 원하는 자료형을 적어서 강제로 형태를 바꾼다. 데이터 손실이 일어날 수도 있지만 "내가 의도한 거니까 그냥 해!"라고 지시하는 것이다. 특히 정수 나눗셈에서 아주 단골로 쓰인다.
#include 

int main() {
	int distance = 10;  //10미터 이동
	int time = 3;       //3초 소요
	
	// 초보자의 실수 (암시적 형변환에 의존)
	float speed1 = distance / time;
	
	// 숙련자의 코드 (명시적 캐스팅 사용)
	float speed2 = (float)distance / time;
	
	printf("잘못된 속도 : %f\n", speed1); //3.000000 출력 (소수점 날아감)
	printf("정확한 속도 : %f\n", speed2); //3.333333 출력
}

speed1 설명 :

C언어에서 정수 / 정수의 결과는 무조건 정수이다. 10 나누기 3을 하면 소수점 아래가 잘려나가고 몫인 3만 남는다. 그 뒤에 float 그릇에 담아도 이미 소수점이 날아간 상태라 3.0이 된다. (데이터 손실)

speed2 설명 :

계산을 하기 직전에 distance 앞에 (float)를 붙였다.
  1. distance가 강제로 10.0f(실수)로 변환된다.
  2. 그 다음 10.0f / 3 (실수 / 정수) 연산이 된다.
  3. 이때 암시적 형변환이 발생하여 정수 3도 실수 3.0f로 바뀌고, 결과적으로 3.33333.... 이라는 정확한 소수점을 얻게 된다.
---------------------------

3. 주의사항

주의점 1 : '데이터 잘림(Trunction)'의 물리적 원리

큰 자료형(uint32_t)에서 작은 자료형(uint8_t)으로 캐스팅할 때, 컴파일러는 반올림 같은 친절한 수학적 처리를 해주지 않는다. 기계어 레벨에서 casting은 그저 ""앞부분 비트를 칼로 잘라버리고 남은 뒷부분만 우겨넣는 것"" 이다. 0x12345678을 1바이트로 캐스팅하면 앞의 123456은 증발하고 0x78만 남게 된다.

주의점 2 : 부호 확장(Sign Extension)의 마법

음수를 다룰 때 발생하는 현상이다. 1바이트짜리 -5(0xFB)를 4바이트짜리 정수로 형변환하면 어떻게 될까?

주의점 3 : Signed vs Unsigned의 비교

C언어에서 부호 있는 정수(int)와 부호 없는 정수(unsigned int)를 서로 비교연산자(<, >)로 비교하면, 컴파일러는 부호 있는 정수를 몰래 부호 없는 정수로 암시적 형변환을 해버린다. 결과적으로 -10이 5보다 크다고 판단하는 기형적인 버그가 발생한다. 데이터를 비교할 때는 양쪽의 자료형 규격을 캐스팅으로 똑같이 맞춰주는 것이 중요하다. -----------------------------------------

개념 요약

------------------------------------------- 다음 공부 일기에서는 C언어에서 가장 중요한 개념이라고 생각되는 포인터(pointer)에 대해 설명할 예정이다. 가장 중요한 개념이기 때문에 정의에 입각한 정확한 설명과 동시에 적절한 활용 사례를 제시하도록 할 것이다. 이제 왕초보 임베디드 공부 일기, 즉 C언어 공부 일기의 3분의 2정도가 끝났는데, 이 일기가 끝나면 장비를 사용하여 여러 임베디드 실습을 하는 것을 연재해보려 한다. 그 때에는 글뿐만 아니라 다른 형태로도 학습 활동을 보여주려고 한다.