이전에 설명한 것처럼 C 언어에서 사용되는 정수는 8진수, 10진수, 16진수가 있다. 아래의 프로그램은 변수에 각각 진수들을 저장하고 출력하는 프로그램이다.
05 행에서 변수 a, b, c를 int 타입으로 선언한다.
07 행에서 a 변수에 10진수 21를 대입한다.
08 행에서 b 변수에 8진수 34를 대입한다. (앞에 0 가 붙으면 8진수를 의미)
09 행에서 c 변수에 16진수 AC를 대입한다. (앞에 0x 가 붙으면 16진수를 의미)
11 행에서 모든 변수를 10진수로 출력한다. (8진수와 16진수가 자동으로 10진수로 변환되어 출력)
13 행에서 모든 변수를 각각의 진법에 맞게 출력한다.
%o : 8진수
%x : 16진수
출력 결과는 아래와 같다.
위의 프로그램에서 가장 중요한 점은 정수 값을 표현하는데 사용되는 바이트 수이다. 프로그래밍 언어에 따라 해당 바이트 수는 차이가 있지만
C 언어에서는 정수를 표현하기 위해 다음과 같은 크기를 제공한다.
데이터 타입 |
크기 |
표현 범위 |
short |
2 바이트 |
-32,768 ~ 32,767 |
int |
2 바이트 / 4 바이트 |
-32,768 ~ 32,767 / -2,147,483,648 ~ 2,147,483,647 |
long |
4 바이트 |
-2,147,483,648 ~ 2,147,483,647 |
short, long 타입은 크기가 고정적인데 비하여 유독 int 타입만 2/4 바이트로 표현된것은 C 언어를 컴파일 하는 컴파일러에 따라 크기가 차이가 나기 때문이다.
따라서 자신의 컴파일러가 데이터 타입을 얼만큼의 바이트로 표현하는지 알아야 할 때에는 "sizeof"라는 함수를 사용하면 된다.
"sizeof" 함수는 데이터 타입이나 변수의 크기를 알아내는 함수로서 크기의 단위는 바이트 수이다. 사용법은 아래의 프로그램을 참고하면 된다.
10 ~ 13 행에서 변수들의 크기를 알아낸다.
14 ~ 16 행에서 데이터 타입들의 크기를 알아낸다.
실행 결과는 아래와 같다.
자 그렇다면 "데이터 타입의 크기를 왜 굳이 알아야 할까?" 라는 의문이 들수도 있다. 사람들은 수를 표현할 때 자리수와 상관없이 원하는 수를 마음대로 나타낼
수 있다. 그것이 1 이던지, 10 이던지, 10000000000000000000000000000000000000000000000000000000000 이던지 우리가 사용하기 나름이기 때문에 상관이 없다.
그러나!! 컴퓨터의 기억 공간은 제한적이기 때문에 하나의 수를 나타낼 기억 공간도 제한적일 수밖에 없다.
그렇기 때문에 데이터 타입 별로 크기가 정해져 있는 것이다. 이러한 제한적인 크기의 데이터 타입이 표현할 수 있는 수 역시 제한적일 수밖에 없다.
예를 들면 크기가 4 비트(이해를 돕기 위해 바이트 대신 비트 사용)인 변수가 표현할 수 있는 수의 범위는 0000 ~ 1111 까지이다.(음수는 고려하지 않음)
컴퓨터는 2 진수로 이루어지기 때문에 0000 ~ 9999가 아닌 0000 ~ 1111 범위가 4 비트가 표현 가능한 수의 범위이다.
다음과 같은 식이 존재한다고 가정해보자.
1 1 1 1
+ 1
=================
1 0 0 0 0
위와 같은 식이 바로 문제가 되는 식이다. 우선 2 진수의 덧셈을 한 결과는 "1 0 0 0 0"이다. 문제는 해당 프로그램에서 사용된 변수의 크기가 위에서 가정하였듯이
4 비트라면 빨간색으로 표시된 1(캐리=올림수)는 표현할 수 없게 되고, "0 0 0 0"만 저장되어 결국 값은 "0" 이 되버리는 현상이 발생한다.
이처럼 저장 공간이 부족하여 이상한 결과가 나오는 현상을 "오버플로우(overflow)" 라고 한다. 아래의 프로그램을 통하여 오버플로우 현상에 대해 알아보자.
05 행에서 short 타입의 변수 s를 선언한다.
07 행에서 3만+4만의 결과를 변수 s에 대입한다.
친절하게도 컴파일 과정에서 경고가 나타난다. (오버플로우 발생)
그러나 warning은 말 그대로 경고일뿐 프로그램의 실행은 가능하다. (물론 정상적인 실행을 보장하지 못함)
실행 결과 프로그래머가 원하는 70000이 아닌 4464 라는 이상한 값이 나와버렸다. 이런 현상이 바로 오버플로우이다.
* 언더플로우라는 것도 존재하는데 이는 데이터 타입이 표현할 수 있는 최소값 보다 연산된 결과가 더욱 최소인 경우를 말한다
이런한 현상을 방지하기 위한 방법으로는 2 가지의 방법이 있다.
방법 01. 표현할 수 있는 범위가 더욱 넓은 데이터 타입을 사용한다. (int, long 등)
방법 02. unsigned 타입을 사용한다.
방법 01은 이해가 당연히 가겠지만 02의 경우에는 이해가 잘 되질 않을 수 있으니 설명을 한다. 다른 사람이 코딩을 한 C 언어 프로그램을 보다 보면
데이터 타입 앞에 unsigned가 붙은것을 볼 수 있는데, unsigned가 붙으면 음수는 표현 하지 않고 0 이상의 수만 표현하게 된다.
이를 표로 정리하면 다음과 같다.
데이터 타입 |
크기 |
표현 범위 |
short |
2 바이트 |
-32,768 ~ 32,767 |
unsigned short |
2 바이트 |
0 ~ 65,535 |
int |
2 바이트 / 4 바이트 |
-32,768 ~ 32,767 / -2,147,483,648 ~ 2,147,483,647 |
unsigned int |
2 바이트 / 4 바이트 |
0 ~ 65,535 / 0 ~ 4,294,967,295 |
long |
4 바이트 |
-2,147,483,648 ~ 2,147,483,647 |
unsigned long |
4 바이트 |
0 ~ 4,294,967,295 |
C 언어에서 사용되는 실수는 소수점 표현과 지수 표현이 있다고 이전 포스팅에서 잠깐 언급한 적이 있다. 변수의 선언과 대입은 이전 포스팅에서도
계속 언급하였으니 별 다른 설명 없이 바로 프로그램을 보도록 하자.
05 행에서 변수 a,b를 double 형식으로 선언한다.
06 행에서 변수 a에 소수점 표현으로 된 소수를 대입한다.
07 행에서 변수 b에 지수 표현으로 된 소수를 대입한다.
실행 결과는 다음과 같다.
실수 데이터 타입에는 double만 있는 것이 아니라 다른 것들도 존재하는데 이를 표로 나타내면 다음과 같다.
위의 표(티스토리 내에서 작성하려 했으나, 지수와 분수를 입력하는 부분을 찾을 수 없어 한글에서 작성 후 캡쳐한 사진입니다. 양해 부탁드립니다) 처럼
long double의 경우 시스템 마다 다르기 때문에 "정수 데이터 타입"에서 본 "sizeof" 연산자를 사용하여 크기를 알아볼 수 있다.
코딩이 크게 다르지 않기 때문에 본 과정은 생략한다.
우선 영문자 A/a 와 B/b 의 차이는 1 차이이다. B/b 와 C/c의 차이도 1이다. 또한 영대문자 A와 영소문자 a의 차이를 이해하면(본인이 찾아보길 바라며, 설명 하지 않음)
다음과 같은 프로그램을 만들 수 있다.
05 행에서 char 타입의 ch 변수에 문자 'A'를 대입하며, 변수 b를 선언한다.
06 행에서 b의 값을 ch+1로 지정한다. (즉, A의 다음 문자인 B를 뜻함)
실행 결과는 아래와 같다.
아래의 프로그램은 07 행의 설명처럼 영소문자를 영대문자로 변환하는 프로그램이다.
09 행에서 변환할 소문자를 입력 받는다.
11 행 끝 부분을 보면 소문자와 대문자 간의 차이를 이해하고 이를 변환하는 식을 볼 수 있다. (ch - 'a' + 'A')
실행 결과는 아래와 같다.
* 아직 조건문(조건에 따라 맞으면 수행1 이라는 부분을 수행하고, 조건에 틀리면 수행2 라는 부분을 수행하는 개념)을 배우지 않았기 때문에 문자를 입력 받아서
해당 문자가 대문자면 소문자로, 소문자면 대문자로 변환하는 프로그램을 만들 수는 없다. 그러나 나중에 포스팅 할 조건문을 배우게 되면 아주 간단히 코딩 할 수 있다.