char 연산이 이상하다?

libft과제를 진행 중 신기한 현상을 보았는데요. C에서 산술연산을 할 경우 type의 범위를 넘어가면 overflow나 underflow가 발생합니다. 즉 아래와 같은 코드에서는 모두 underflow가 발생할거라고 예상할 수 있습니다. 두 연산의 결과 모두 해당 타입의 MAX값을 출력하게 되겠죠. 그런데 과연 그럴까요?

Untitled

아래의 결과처럼 우리의 예상과는 달리 unsigned char의 연산은 underflow가 발생하지 않고 마치 미리 int형으로 type casting을 한 것 마냥 연산결과가 나온 것을 알 수 있습니다.

Untitled

분명 두 연산 모두 unsigned type을 연산해서 그 보다 더 넒은 범위의 type으로 type casting하여 출력하였는데 이게 어찌된 일일까요? 그 해답을 stackoverfolw 커뮤니티에서 찾을 수 있었습니다.

C는 표현식에 사용되는 피연산자의 정수 유형을 암시적으로 자동으로 변경하도록 설계되었습니다. 언어에서 컴파일러가 피연산자를 더 큰 유형으로 변경하거나 부호를 변경하도록 강제하는 몇 가지 경우가 있습니다.

즉 어떤 연산을 할 때 우리가 설정한 type이 아니라 다른 type으로 암시적으로 형변환이 될 수도 있다는 뜻입니다. 덕분에 아래 사진처럼 명시적으로 unsigned char 타입으로 변환하여도 결과는 똑같습니다.

Untitled

Untitled

그럼 왜 이렇게 헷갈리게 특정 경우에만 암시적 형변환이 발생할까요?

The integer promotions

Formally, the rule says (C11 6.3.1.1):

If an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions.

위는 C의 공식 문서 내용인데요. int가 원래 유형의 모든 값을 나타낼 수 있는 경우(비트 필드의 경우 너비에 의해 제한됨) 값은 int로 변환되고 그렇지 않으면 unsigned int로 변환된다고 합니다. 이를 정수 프로모션(**integer promotions)**이라고 합니다. 즉 unsigned char는 int의 범위로 표현 가능하기에 정수 프로모션이 발생한 것입니다. int는 해당 운영체제가 가장 빠르게 접근할 수 있는 type이기 때문에 이런 정수 프로모션이 발생하는 것 같습니다.

그럼 우리의 의도대로 underflow된 결과를 얻을 수는 없는걸까요? 조금 돌아가는것 같지만 아래와 같이 type casting을 하면 underflow된 결과를 얻을 수 있습니다.

Untitled

Untitled

이런 신기한 규칙도 존재하니 연산 결과가 의도와 다르면 정수 프로모션이 원인일 수도 있다는 것도 고려하면 좋을 것 같습니다.