여기서는 변수의 데이터 형과 변수명에 대해 이야기해보겠습니다.
우리가 밥을 먹을 때 밥은 밥 그릇에, 국은 국 그릇에, 반찬은 접시 혹은 그에 맞는 그릇에 담아냅니다.
변수의 데이터 형식도 똑같습니다-
숫자 정보를 가진 데이터는 숫자 형식의 그릇에 담고, 문자 정보를 가진 데이터는 문자 형식의 그릇에 담아냅니다.
숫자는 다시 정수형, 실수형으로 나누어지고, 숫자나 문자 모두 정보의 크기에 따라 다른 형식을 가지고 있습니다.
각 형식의 이름들을 확인해 볼까요?
문자형
char
정수형
short // int // long
실수형
float // double // long double
응? 문자형은 하나인데 정수형과 실수형은 3개씩이네요?
그 이유는 크기가 다르기 때문입니다.
#include <stdio.h> #include <stdlib.h>
int main(void) { printf("Size of char data = %d byte \n", sizeof(char)); printf("Size of short data = %d byte \n", sizeof(short)); printf("Size of int data = %d byte \n", sizeof(int)); printf("Size of long data = %d byte \n", sizeof(long));
printf("Size of float data = %d byte \n", sizeof(float)); printf("Size of double data = %d byte \n", sizeof(double)); printf("Size of long double data = %d byte \n", sizeof(long double));
system("PAUSE");
return 0; } |
다음의 소스코드를 작성해서 컴파일후 실행해 봅시다.
각 변수들의 크기를 한눈에 볼 수 있네요- 소스코드에 대한 설명은 생략하겠습니다.
각 변수형들의 크기가 1~12 byte 라고 하는데 이게 뭔가요?그림으로 알아보도록 해봅시다.일반적으로1 byte는 8 bit로 구성이 되어있습니다. 물론 일반적이기 때문에 절대적이지는 않습니다-
그럼 이 1 bit 라는게 무엇인가요? 1 bit 는 0 혹은 1 과 같은 디지털 정보를 가지고 있는 가장 작은 의미의 방입니다.
이러한 방이 8개가 모여서 1byte가 되는것이고. byte가 모여서 KByte, MByte, GByte 등등....
그럼 bit 와 byte는 이해하겠는데 이걸로 뭐 어쩌자는건지 봅시다.
위에서 이야기 했듯이 bit 에는 0 혹은 1 과같은 디지털 정보, 즉 이진수로 값을 저장합니다.
bit 하나로 표현 할수 있는 수는 0 혹은 1 , 두가지 뿐이지요. ( 2¹ = 2 )
bit 두개로는 [ 00, 01, 10, 11 ] 로 이진수를 십진수로 표현하면 [ 0 , 1 , 2 , 3 ] 네가지 입니다. (2² = 4)
그럼 1 byte = 8 bit 로는 몇가지를 표현할 수 있을까요?2 ^ 8 = 256 가지 입니다.
숫자로 표현하면 0 ~ 255 까지 표현할수 있습니다.
다시말해 1 Byte 크기의 char 형 데이터 값은 0 ~ 255 까지 저장하고 표현할 수 있습니다...?
char 형은 문자형이라면서요?
문자형 변수도 저장은 0 혹은 1의 값으로 저장이 됩니다.
그럼 어떻게 문자를 화면에 출력하게 할수 있나요?
클릭해서 보세요.
위에 보는 표가
아스키 코드 표 (ascii code table) 입니다.
기계, 컴퓨터에는 기본적으로 미리 숫자에 해당하는 문자가 정해져 있습니다.
미리 정해져 있는 내용들을 0 ~255 까지 표로 만들어 필요할 때 볼 수 있습니다.
예를 들어 char 형의 변수 값이 65 라면 화면에 글자로 표현하게 되면 'A' 라는 값이 나오는거지요.
#include <stdio.h> #include <stdlib.h>
int main(void) { char char_data;
char_data = 65 ;
printf("char_data is %c \n", char_data); printf("ascii code of %c is %d \n", char_data, char_data);
system("PAUSE"); return 0; }
|
다음의 소스 코드를 작성해서 컴파일후 실행해서 결과를 확인해 봅시다.
우리는 코드에서 char 형의 변수 char_data에 65라는 값을 저장 했습니다.
printf("char_data is %c \n", char_data); printf("ascii code of %c is %d \n", char_data, char_data); |
그리고 화면에 char_data 값을 출력합니다.
여기서 %c 는 문자형으로 출력하라는 의미이고 %d 는 10진수의 숫자로 출력하라는 의미입니다.
자세한것은 printf 함수에 대해 이야기 할 때 다뤄봅시다.
실제로 우리가 보는 결과를 보면 char_data is Aascii code of A is 65라고 나옵니다.
우리는 단지 char_data 라는 변수 하나만으로 두가지의 출력값을 본것입니다.
정리하자면 char 형의 변수는 기본적으로 0~255 범위 내의 값을 저장하고 있고
이것을 문자형으로 출력할 때는 값에 해당하는 아스키 코드 값을 출력해주는 것입니다.
그럼 이번엔 정수형에 대해 이야기를 해봅시다.
정수형 변수중 가장 자주 쓰이는 int 를 기준으로 이야기해볼게요.
int 형은 4byte 의 크기를 가지고 있습니다.그럼 총 4byte * 8bit = 32bit 입니다.
32비트면 표현할 수 있는 정보는 2 ^ 32 = 4294967296 가지네요.
그럼 0 ~ 4294967295 까지 표현할 수 있을까요?
결론 부터 말하자면 틀리진 않았지만 맞지도 않았습니다...?
무슨말이냐면 정수는 우리가 모두 알듯이 양수가 있고, 음수가 있습니다.
음수도 표현할 줄 알아야지요^^
부호는 32 bit 중에서 가장 왼쪽에 있는, 최상위 비트를 통해 결정합니다.
그럼 이러한 부호비트를 제외하고 31 bit 만이 정수의 값을 표현할수 있겠지요?
결국 2 ^ 31 = 2147483648 이니까, -2147483648 (- 2^31 ) ~ 2147483647 ( 2^31 -1) 의 범위를 표현할수 있지요.
#include <stdio.h> #include <stdlib.h>
int main(void) { int int_data;
int_data = 2147483647 ; printf("int_data is %d \n", int_data);
int_data = int_data + 1; printf("int_data is %d \n", int_data);
system("PAUSE"); return 0; } |
다음의 소스코드를 작성한 다음 컴파일후 실행하기전에 먼저 소스코드를 분석해봅시다.
int_data = 2147483647 ; printf("int_data is %d \n", int_data); |
우선 int 형의 변수의 양의 범위중 최대값인 2147483647 을 넣고 화면에 출력합니다.
int_data = int_data + 1; printf("int_data is %d \n", int_data); |
그리고 그 다음 최대값을 저장했던 변수에 1 을 더한 후 다시 화면에 출력합니다.
그러면 화면에는 어떤 결과가 나올지 실행을 한번 해봅시다.
우리는 양수값에 1을 더해 주었는데 어째서 마지막 출력값은 음수값.
그것도 음수값중 int형의 최소값이 나오는걸까요?
이런 현상이 일어나는 이유에 대해 이야기 해봅시다.
다음과 같은 과정을 통해서 결과값은
부호 bit가 1이 되고 나머지는 0 의 값을 갖습니다.
결국 양수의 최대값을 넘어가버리면 음수가 되어버리는 현상이 일어나는 것 이지요.
음수는 2의 보수를 취해준 값을 사용하는데,
1000 0000 0000 0000 0000 0000 0000 0000 의 2의 보수는 반전 후
0111 1111 1111 1111 1111 1111 1111 1111 + 1 이므로
1000 0000 0000 0000 0000 0000 0000 0000 = 2 ^ 31 = 2147483648 입니다.
결국 - 2147483648 라는 음수의 최대값이 화면에 출력되는 것이지요.
나는 부호는 필요없이 정수만을, 그리고 더 큰값이 필요하다!
라고 하시는 분들은 변수앞에 unsigned 를 붙여주시면 됩니다.
참고로 실제로 사용하는 변수형에는 signed 가 생략되어 있습니다. 써도그만 안써도 그만인 signed !
#include <stdio.h> #include <stdlib.h>
int main(void) { unsigned int int_data;
int_data = 2147483647 ;
printf("int_data is %u \n", int_data); printf("int_data is %u \n", int_data + 1 );
int_data = 4294967295 ;
printf("int_data is %u \n", int_data );
printf("int_data is %u \n", int_data + 1 );
system("PAUSE");
return 0; } |
다음의 소스 코드를 작성해서 컴파일후 실행해 봅시다.
결과를 보면 아까와는 다릅니다.
unsigned int 의 최대값 4294967295 (= 2^32 -1) 까지 출력이 되네요.
int_data = 2147483647 ;
printf("int_data is %u \n", int_data); printf("int_data is %u \n", int_data + 1 ); |
printf 함수 안을 자세히 보시면 조금 다른것이 있습니다.
%u 가 있는데요. 이것은
unsigned 형태의 정보값을 가져올 때 사용합니다.
우리가 선언하고 사용하고 있는 int_data 가 unsigned int 형이기때문에 %d 가 아닌 %u 를 사용하는것이지요.
int_data = 4294967295 ;
printf("int_data is %u \n", int_data );
printf("int_data is %u \n", int_data + 1 ); |
여기서는 unsigned int 의 최대값을 int_data 에 저장한 후 화면에 출력할 때는 저장되어 있는 값을 출력하고,
그 다음 줄에서는 저장되어 있는 값 +1 의 값을 출력합니다.
응? 그런데 이번에는
결과가 0 이 나오네요. 이유를 한번 살펴봅시다.
이번에도
오버플로우 (Overflow) 현상이 일어났네요.
최대값에서 1이 더해지면서 unsigned int 의 범위 내의 값은 모두 0 이 되고 범위 외로 값이 넘어가버립니다.
덕분에 우리가 가지고 있는 공간내에는 모두 0 이 들어가있는 결국 연산의 결과값은 0이 되버렸네요.이렇듯 우리가 연산을 할때 값이 넘어가버리는 오버플로우 현상이 일어나지 않도록 조심해야겠지요?
short 형과 long형은 단지 공간의 차이를 가지고 있을 뿐
int 형과 큰 차이가 없습니다.
공간의 차이는 범위의 차이를 가지고 오겠지요? unsigned 도 똑같이 적용됩니다.
이제 마지막으로 실수형을 살펴봅시다.
실수형도 대표로
float 형을 알아보도록 할까요?
#include <stdio.h> #include <stdlib.h> int main(void)
{ float float_data; float_data = 3.14 ;
printf("float_data is %f \n", float_data);
system("PAUSE");
return 0; } |
다음의 소스코드를 작성해서 컴파일후 실행해 봅시다.
화면에 소수점을 표현하는 값이 출력되었습니다.
float은 실수형 변수로서 소수까지 저장하고 표현할 수 있는 변수 입니다.
또한 float은 int 와 같은
4 byte 입니다.
그런데 float의 범위를 먼저 말씀 드리자면
3.4*10-38 ~ 3.4*1038 입니다.
어마어마한 범위를 가지고 있습니다. 어째서 int 와 같은 4 Byte 인데 이렇게 범위의 차이가 클까요?
구조를 알아보면 바로 알 수 있을듯 하니
어디 한번 풀어 헤쳐 봅시다.
우선 float 형의 구조는 이러하고 계산 방법까지 확인 하였습니다.
예를 들어 한가지를 표현해보면.
부호 bit = 0
지수 bit = 128
유효자리 = 2 ^ 15 = 32768
이라면, 그 값은
부호는 양의 값을 가지게 되고
(-1) ^ (0) * ( 1.32768 ) x 2 ^ (128 - 127) = 1.32768 x 2 = 2.35536
위와 같은 값을 가지게 됩니다.
이해가 되셨나요?
그러면 int 형보다 float 형이 같은 크기의 정보량으로 더 많은 범위를 사용할 수 있으면 float 이 더 좋은것 아닐까요?
물론 float 이 더 넓은 범위의 숫자를 표현할 수 있고 소수점 아래 까지 표현할수 있어 좋아보일 수도 있지만.
float은 연산 도중 손실되는 부분이 있어 정확하다고 보긴 어렵습니다.
또한 연산을 통해 값을 표현하기 때문에 표현할 수 없는 수도 있고요.
쉬운 예로 float은
0 을 정확하게 표현할 수 없습니다.
유효자리에 아무리 작은 수가 들어가고, 지수가 아무리 작아지더라도
0이 아닌 그에 준하는 수 입니다.
1 * 2 ^ (-127) = 5.8774717e-39
근사한 값을 이용하여 수를 표현하는 방식이기 때문에 int 형보다 정확하다고 볼 수는 없습니다.
또한 float 형의 변수를 많이 사용하게 되면
전체적인 프로그램의 속도가 많이 줄어드는 모습을 볼 수 있습니다.
float 형을 사용하는 것은 프로그래머의 의도에 따른 것이지만,
사용을 할 때는 변수의 범위와 손실을 고려해야합니다.
실수형의 또 다른 변수형
double 도 같은 방식을 통해 사용되고
지수 bit 가 11bit ,
유효자리가 52bit 입니다.
그만큼
범위가 넓어지고 손실도 적어지지만, 손실이 있다는 점은 변하지 않습니다.
이렇게 해서 변수의 기본적인 데이터형에 대해 알아보았습니다.
이외에도
포인터형 변수,
배열, 구조체 등등 상위 개념의 변수들도 있고 다양한 변수형이 있습니다.
하지만 기본 변수형을 통해 다른 변수들의 구조와 정보를 쉽게 이해할 수 있습니다.
덧글
키세츠 2011/04/05 09:25 # 답글
오버플로우가 발생하면 그냥 0만 출력하고 끝나나요?아니면 실행이 멈추거나 하진 않나보죠?
harlequinus 2011/04/05 13:10 #
오버플로우가 일어나면 넘어가는 값을 삭제가 됩니다.간혹 또 다른 어떤 변수에 영향을 주는 경우가 발생할 수 있는 위험이 있지만, 거의 문제없다고 보시면됩니다.
아니, 오버플로우가 일어나는 자체가 문제일까나요?
실행이 멈춘다거나 오류메세지를 출력해주는건 프로그래머가 구현할 수 있지만,
의도적으로 오버플로우 현상을 이용하여 프로그램을 설계하시는 부분도 있습니다.
키세츠 2011/04/06 17:35 # 답글
답변 감사합니다.근데 일일연재 아니셨나요? 기다리다가 퇴근합니다.
집에서는 애 봐야 되서 이글루는 무리....
harlequinus 2011/04/07 11:01 #
원래는 일일연재를 생각했었는데 뭔가 점점 양이 많아지고 정리가 안되고 있어서요^^기다리시는 분이 계실줄은 몰랐는데, 고맙습니다..ㅜ
최대한 빠르게 다시 시작할게요-