7.4 Type Conversion


컴퓨터는 엄격해서 16-bit integer와 32-bit integer 간의 연산도 허용하지 않는다. 

C는 서로 다른 type끼리의 연산을 허용한다. integer, floating-point numbers, characters

implicit conversion: 프로그래머의 관여 없이 컴파일러에서 자동적으로 변환하는 것.

다음의 경우에 implicit conversion이 이루어진다.

1. 산술 연산이나 논리연산의 피연산자(operand)가 같은 형이 아닌 경우(usual arithmetic conversions)

2. assign하는 변수(좌변)와 우변의 표현식의 type이 다를 때

3. 함수를 호출할 때 argument가 해당하는 parameter와 type이 다를 때

4. 함수의 return type과 return statement에 있는 expression의 type이 다른 경우

여기서는 앞의 두가지 경우를 다루고, 나머지는 9장에서 다룬다.


The Usual Arithmetic Conversions

binary, arithmetic, relational, equality operation에서 피연산자들의 type이 다를 때

"narrow": 거칠게 표현해서, A type을 저장하는 데 B type을 저장하는 것 보다 더 적은 바이트가 필요하다면, A type이 B type보다 더  narrow하다고 한다.

promotion: 서로 다른 두 type이 피연산자일 때, 더 narrow한 type을 다른 type으로 변환하는 것. 더 적은 범위를 표현하는 type을 더 넓은 범위의 type으로 변환

integral promotion: char, short int 를 int로 변환


promotion 단계

두 타입중 하나가 floating type인 경우

float -> double -> long double

두 타입 모두 floating type이 아닌 경우

int -> unsigned int -> long int -> unsigned long int


int가 unsigned int로 변환되는 것에 유의하자. unsigned int 10과 int -10을 비교할 때 -10은 unsigned int로 promote되면서 4,294,967,296이 더해지면서(4,294,967,295가 unsigned int의 가장 큰 값) 이상한 값이 나온다. unsigned integer는 최대한 사용하지 않는 것이 좋고, 만약에 쓰게 된다면 signed integer과 엮이는 일이 절대 없어야 한다.


int + char = int

int + short = int

unsigned int + int = unsigned int

long + unsigned int = long

float + unsigned long = float

double + float = double

long double + double = long double


Conversion During Assignment

assignment에 있어서는 arithmetic conversion이 아닌 더 단순한 룰이 적용된다.

우변에 있는 표현식의 type이 좌변의 변수와 같은 type으로 변환된다.

int = char -> 우변이 int로 변환

double = float -> 우변이 double로 변환

int i;

i = 842.97 -> 우변 842가 int로 변환되어 i = 842가 된다.

우변의 type을 더 narrow하게 변환해야 하는 경우, 의미없는 결과가 나올 수 있다

ex) i = 1.0e20;

부동 소수점 숫자를 입력하는 경우 기본적으로 double type이다. 만약 float으로 저장하고 싶다면, 뒤에 소문자 f를 붙인다.

3.14159 -> double

3.14159f -> float


C99에서의 usual arithmetic conversion에 대한 설명은 생략.


Casting

컴파일러에서 암시적으로 하는 것이 아닌, 프로그래머가 명시적으로 형변환을 하는 것

( type-name ) expression


floating type의 소수점 구하기

float f, frac_part;

frac_part = f - (int) f;


컴파일러의 기존 규칙과 다른 규칙을 적용하고 싶을 때

float q;

int a, b;

a = 3, b = 2;

q = a/b;    // q는 float이지만 1.5가 아닌 1.0이다.

q = (float) a/b;    // q = 1.5


오버플로우를 피하기 위해

long long int i;

int j;

j = 1000000;

i = (long long int) j * j;    

// overflow가 일어나지 않도록, int의 범위를 벗어나는 결과가 예상되면 casting해줌

printf("%lld\n", i);


( type name ) 은 unary operator임. binary operator보다 더 우선순위가 빠르다. ( long ) i * j; 는 i를 long으로 변환시킨 후에 j와 곱한다.


7.5 Type Definitions


typedef int Bool;

Bool flag; /* same as int flag; */

Bool이라는 type을 정의하고, flag라는 변수를 Bool type으로 선언. 사실 int로 선언한 것과 다르지 않다.


Advantages of Type Definitions

이름을 잘 지으면 더 이해하기 쉬운 코드를 짤 수 있다. 또 나중에 수정하기가 쉽다

ex) typedef float Dollars;    // 돈에 관한 변수임을 알기 쉽고, 만약 float 대신 double이 필요하다면 모둔 변수의 선언 부분 대신 typedef 부분만 수정하면 됨


Type Definitions and Portability

같은 이름의 type이 서로 다른 시스템에선 다른 범위를 나타낼 수 있기 때문에, typedef를 이용해 type의 범위를 지정하는 것이 코드의 portability에 도움이 될 수 있다.

C99에서는 <stdint.h>를 이용해 변수에 몇 비트를 할당할 것인지 지정해 줄 수 있다. 예를 들어 int32_t는 32bit의 signed integer를 의미한다. 

typedef int32_t Int32; // 새로운 32비트의 signed integer 'Int32' type 정의


7.6 The sizeof Operator


타입을 저장하려면 메모리가 얼마나 필요한가?

sizeof ( type-name )


이 결과는 type-name(type의 이름일 수도 있고, 변수일 수도 있다)를 저장하는 데 몇 바이트가 필요한지 를 나타내는 양의 정수이다. sizeof의 type은 size_t라는 unsigned 정수형의 type이다. 괄호 안에 char를 넣으면 1, int는 (보통) 4. 이 값은 unsigned long의 범위를 벗어날 수도 있다. 그러나 casting을 해주지 않고도 overflow 걱정 없이 값을 나타낼 수 있다.

printf("Size of int: %zu\n", sizeof(int));    // C99 only


--추가

hexadecimal floating constants의 장점: 10진수 형태로 나타낸 소수는 2진수 형태로 변환될 때 나타나는 rounding error에 영향받기 쉽지만, hexadecimal 의 경우에는 그렇지 않다. 따라서 더 정확한 표현이 가능하다. 특히 숫자가 작을수록.



+ Recent posts