5-4-다.산술 변환

C언어는 데이터 타입이 조금 다른 변수끼리라도 자동으로 변환이 가능하면 연산을 허용한다. 다음 예제를 보자.

 

: typeconvert

#include <Turboc.h>

 

void main()

{

     int i,j;

     double d;

 

     i=3;

     d=2.17;

     j=i+d;

     printf("j=%d\n",j);

}

 

정수형의 변수 i와 실수형의 변수 d를 더해 정수형 변수 j에 대입하고 있다. 이 예제를 컴파일하면 경고가 발생하기는 하지만 에러없이 컴파일되며 실행도 잘 된다. 정수형과 실수형은 크기도 다르고 메모리내에 값을 기억하는 방식도 다르다. 따라서 원칙을 따지자면 정수형 변수와 실수형 변수의 덧셈은 허용되지 않으며 실제로 파스칼같은 언어에서 이런 연산문은 에러로 처리된다.

그러나 C는 타입이 달라도 자동으로 두 타입을 맞추어 일치시킨 후 연산하는데 C의 이런 특성을 융통성이라는 장점으로 표현하기도 하지만 엄격하지 못한 타입 체크라는 단점으로 지적되기도 한다. 당장 쓰기에는 편리하지만 이런 서비스가 잠재적인 에러의 원인이 될 수도 있다. 다른 타입의 데이터가 한 수식에 동시에 사용될 때 연산을 위해 데이터형을 임시로 변환하는 이런 동작을 산술 변환이라고 한다. 산술 변환에는 상승 변환, 하강 변환, 부호 변환 세가지 종류가 있다. 위 예제를 통해 이런 변환에 대해 연구해 보자.

j=i+d; 연산문에서 상승 변환과 하강 변환이 동시에 일어난다. 먼저 정수형 변수 i와 실수형 변수 d를 더하기 위해 i가 잠시 실수형으로 확장된다. 피연산자 중 하나가 실수형이므로 + 연산은 실수 연산을 해야 하며 그래서 i을 d에 맞추는 것이다. 연산중에 정확성을 잃지 않기 위해 가급적이면 큰 타입으로 변환되는데 4바이트의 정수형이 8바이트의 실수형으로 바뀌었으므로 이를 상승 변환이라고 한다. 이 결과 i+j는 5.17이라는 실수값으로 평가된다.

덧셈을 한 결과가 정수형 변수 j에 대입될 때는 대입받는 쪽의 타입에 맞추기 위해 하강 변환이 발생한다. 실수형의 수치 5.17은 정수형 변수에 담을 수 없으므로 소수점 이하를 버리고 정수형으로 바꾼 후 5만 대입되고 0.17은 버려진다. 실수형의 큰 타입에서 정수형의 작은 타입으로 변환되었으므로 하강 변환이라고 한다.

C는 이런 식으로 데이터 타입이 달라도 적절한 형 변환에 의해 연산이 이루어지도록 한다. 그러나 형 변환에 의한 결과나 부작용에 대해서는 경고만 보여줄 뿐 책임지지 않는다. 만약 위 예제에서 5.17이라는 결과를 바랬다면 이는 연산 결과를 저장할 변수 j를 정수형으로 선언한 프로그래머의 잘못이지 컴파일러의 잘못이 아니다. 컴파일러는 어디까지나 미리 정해진 규칙대로 산술 변환을 하여 연산할 뿐이다. 다음은 C의 산술 변환 규칙이다.

 

이항 연산시 양변의 타입이 다르면 큰 쪽으로 상승 변환된다. 그래야 가급적이면 정확한 계산을 할 수 있다.

대입 연산시 좌변의 타입을 따른다. 값을 대입받을 변수의 능력치를 초과할 수는 없기 때문에 대입되는 값이 변수보다 더 크면 잘라낸다.

함수 호출시 실인수와 형식인수의 타입이 다르면 형식인수의 타입을 따라간다. 함수 호출 과정에서의 인수 전달은 결국 대입 동작이기 때문에 2번 규칙과 같은 규칙이다.

캐스트 연산자를 사용하면 강제로 타입을 변환할 수 있다. 이 변환은 암시적인 산술 변환 규칙이 아니라 사용자가 직접 지정한 명시적 변환이다.

수식내에서 사용될 경우 char, unsigned char, enum형은 int형으로 자동 확장되며 float형은 double형으로 확장된다.

 

만약 번 규칙이 없다면 short a=20000, b=30000일 때 int c=a+b의 결과가 50000이 되지 않을 것이다. short끼리 더한 결과가 short가 되어 버리면 연산중에 오버 플로우가 발생하여 c가 아무리 int 타입이더라도 50000이라는 결과를 대입받을 수 없다. 이런 현상을 방지하기 위해 수식내에서는 타입 확장을 먼저 한 후 연산하도록 되어 있다.

부호 확장이란 부호 있는 작은 타입이 큰 타입으로 확장될 때 발생한다. 1바이트의 char형을 2바이트의 short형으로 변환하거나 short를 int로 변환할 때 부호 확장이 발생하는데 원리는 아주 간단한다. 확장할 수가 1바이트의 0x01이라고 했을 때 2바이트로 확장하면 앞쪽 바이트에 0이 추가되어 0x0001이 된다. 확장에 의해 추가된 바이트에 선행 제로만 붙이면 된다.

음수인 경우는 조금 다르다. 0xff(-1)를 2바이트로 확장하면 0x00ff가 되는 것이 아니라 0xffff가 된다. 이렇게 해야 부호와 값이 그대로 유지된다. 0xff나 0xffff나 둘 다 왜 -1이 되는지는 2의 보수법을 연구해 보면 알 수 있다. 간단히 설명하자면 0xff+1=0x00이고 0xffff+1=0x0000이다. 그러니까 둘 다 -1이 아닌가.