형이 다른 대상에 연산을 하면 대상의 형 변환이 일어나는데, 형 변환에는 몇가지 규칙이 있다. 일반적으로 자동변환이 일어나는 것은 f+i에서와 같이 정보의 손실 없이 변환 가능할 떄뿐이다. 부동소수를 첨자로 사용하는것 같은 상식에 벗어나는 것은 허용되지 안흔다 긴정수를 짧은 정수로 혹은 부동소수형을 정수로 변환한는 수식은 컴파일 할때 경고로 나오겠지만 불가능하지는 않다

문자는 하나의 정수일 뿐이므로 산술식에서 자유롭게 쓸수 있다. 이것은 문자 변환에 상당한 융통성을 부여한다. 문자열 속에 숫자가 있을떄 그것을 해당하는 정수로 바꾸어 주는 함수 aoi를 통해 실험해 볼수 있다.


/* atoi: convert a to integer */


int atoi(char s[])

{

    int i,n;

    

    n=0;

    for (i= 0; s[i] >= '0' && s[i] <= '9'; ++i)

        n = 10 * n + (s[i] - '0');

        return n;

}


제1장에서 설명했던 것처럼 다음 수식은 s[i]에 저장된 문자의 정수 값이 된다.


s[i] - '0'


문자를 정수로 변환한는 또하나의 예는 ASCII 문자 집합에서 대문자를 소문자로 바꾸어 주는 함수 lover를 들수 있다. 만약 문자가 대문자가 아니면 lover는 그것을 그대로 리턴한다.


/* lower: convert c to lower case; ASCII only */


int lower(int c)

{

    if(c >= 'A' && c <= 'Z')

        return c + 'a' - 'A';

    else

        return c;

}


위의 프로그램은 ASCII에만 적용되는데 그것은 대문자와 소문자의 거리가 일정하고 A부터 Z 사이에는 영문자만 존재하기 때문이다. EBCDIC에서는 이 문자 변환이 성립하지 않고 이외의 다른문자체계에서도 안될수 있다.

<ctype.h>는 문자체계에 관계없이 가능한 문자부류 함수를 정리해 준다 예를 들면 함수 tolower(c)는 c가 대문자일 경우 소문자 값을 리턴해 준다. 즉 앞의 lower 함수 대신 tolower를 사용할수 있다. 마찬가지로 다음과 같은 검사


 c >= '0' && c <= '9'


대신에


 isdigit(c)


를 사용할수 있다.

문자를 정수로 변환하는 데는 한 가지 불명확한 점이 이는데 문자형 변수가 부호형인지 무 부호형인지 기계마다 다르다는 것이다 어떤 기계에서 가장 왼쪽비트가 1인 문자는 음의 정수 로 변환한다 물론 왼쪽비트가 1인 경우도 양수로 취급하는 기계도 있다

C의 정의에 의하면 기계의 표준 출력 문자세트의 어떤 글자도 음수가 되지 않는다 그러나 문자 변수에 저장된 임의의 비트 패턴이 어떤 기계에서는 음수로 나타날수 있고 어떤 기계에서는 양으로 나타날수 있다. 문자 변수에 문자가 아닌 숫자가 저장되는 것을 막기 위해서는 프로그램에서 부호형인지 무부호형인지를 확실히 해 주어야 한다.

i>j 같은 관계 수식이나 && 혹은 || 로 연결된 논리 수식은 참일떄 1 거짓일때 0의 값을 같는다 따라서 다음의 지정문은 c가 숫자일때 1 그외경우에는 0의 값이 된다.


d = c >= '0' && c <= '9'


그러나 isdigit 같은 함수는 참일 때 0도 1도 아닌 수를 리턴해 줄수도 있다 if, while, for등의 검사 부분에서도 마찬가지로 참이란 0이 아님을 의미한다

Implicit arithmetic conversions은 거의 기대 하는 대로 된다 일반적으로 + * 같이 두개의 operand(피연산자)를 가진 연산자에서 형이 다를 경우에는 계산을 진행하기 전에 작은 쪽에서 큰쪽으로 변환된다 무부호형 오퍼랜드가 없다면 다음과 같은 간단한 법칙으로 충분하다


long double 이 있으면 둘다 long double로 변환한다

2 그렇지 않고 double 이 있으면 둘다 double로 변환한다

3 그렇지 않고 float가 있으면 둘다 float로 변환한다

4 그렇지 않으면 char 또는 short int로 변환한다

5 그리고 long인 오퍼랜드가 있으면 모두 long으로 변환한다


한가지 주의해야 할 것은 수식중 float는 자동적으로 double로 변환되지 않는다는 것이다 일반적으로  <math.h> 선언되어 있는 함수는 배정도를 사용한다 큰 배열에서는 기억장소를 절약하기 위해서 float를 쓰고 또 기억장소는 충분하더라도 계산시간을 절약하기 위해서 쓸때도 있다

무부호형 오퍼랜드가 개입된 경우의 변환법칙은 더욱 복잡하다 문제는 부호형과 무부형의 비교결과는 기종과 정수형의 크기에 따라 다르다는 것이다 예를들어 int 가 16비트이고 long이 32비트라 하자.

다른형으로 저장된 수를 비교할때 작은범위의 것이 큰 번위의 것으로 변환 되므로 -1L<lU이 된다 비교과정에서 1U가 unsigned long으로 변환된 후 비교가 행해지기 때문이다 같은 방법으로 생각 하면 -1L>1UL이 된다 이경우는 -1L이 unsigned long 형태로 변환되어 큰 양의 정수처럼 보이게 되기 때문이다

변환은 지정문에서 나타나는데 오른편은 왼편과 같은 형으로 변환되어 그것이 결좌의 형이 된다 문자는 위에서기술한 것처럼 부호확장(sigh extension)이든 아니든 정수로 변환된다 긴 정수는 상위 비트를 버림으로써 짧은 정수 혹은 문자로 변환된다. 그러므로 다음과 같은 경우의 c는 값이 변하지 않는다.


    int c;

    char c;

    i = c;

    c =i ;


이것은 부호확장에 관계 없이 성립한다. 그러나 지정의 순서르 바꾸면 정보를 읽을수 있다. 만약 x가    float 이고 i int 라면 x=i i=x에서 모두 변환이 일어나는데 float int로 변환하면 소수부분을 절단한다 double float로 변활될때 소수이하를 버릴지 반올림 할지는 기종에 따라 다르다

함수호출에 의해 매개변수가 함수로 전달될 떄에도 형 변환이 일어난ㄷ. 함수 선언 부분이 없으면  char short int로 변환되고 float double로 된다 이것이 바로 함수가 char이나 float로 호출될 떄에도함수 매개변수들을 int double로 지금까지 선언해온 이유이다

마지막으로 캐스트라 불리는 단일 연산자를 써서 어떤 수식이든 간에 강제로 형 변환을 행할수이싿. 다음의 구조에서 수식은 지정된 형으로 위에서 말한 법칙에 따라 변환된다


(형이름)   수식


수식은 위의 규칙에 의하여 지정된 형으로 변환된다 예를 들어 sqrt란느 라이브러리 루틴은 double 인수를 필요로 하고 그렇지 않으면 예상치 못한 결과를 낳는다(sqt는 <math.h>에 선언되어 있다) 따라서 n정수라면 sqrt에 넘겨주기 이전에 다음과 같이 double 로 변환하여 사용할수있다.


sqrt( (double) n)


cast는 n의 값을 적절한 형으로 바꾸어 주고 n자체는 변하지 않는다는것에 주의해야 한다 cast 연산자는 이장 끝에 표에 정리되어 있는 것처럼 다른 단일 연산와 동일한 높은 순위를 갖는다

매개변수들은 보통 함수원형으로 선언되어야 하고 함수호출이 일어날때는 이 선언으로 인해 자동적으로 변환이 일어난다 그러므로 다음과 같이 함수원형이 주어진 sqrt에서


    double sqrt(double);


다음과 같은 호출의


    root2 = sqrt(2);


정수 값2는 cast를 사용하지 않아도  double 변수 2.0으로 강제 변환된다

표준 라이브러리에는 간단한 preudo-random numer getnerator 와 seed를 초기화 하는 함수가 포함되어 있는데. 이 두함수를 잘 보면 cast연산자를 이해할수 있을 것이다.



unsigned ling int next = 1;


/* rand: return pseudo-random integer on 0..32767 */


int rand(void)

{

    next = next * 1103515245 + 12345;

    return (unsigned int) (next/65536) % 32768;

}


/* srand: set seed for rand() */

void srand(unsigned int seed)

{

    next = seed;

}


예제 2-3 16진수 문자열(0x 또는 0X 모두 포함하는)을 정수로 변환하는 함수 htoi(s)를 작성하라 사용할수 있은 숫자는 0에서 9,a에서 F까지다.