자료형의 정의
프로그램에서의 자료란 메모리상의 어떠한 공간에 기록된 데이터들을 의미합니다.
자료형은 일련의 메모리 공간에 의미를 부여하는 방법입니다.
만약 2개의 구획을 차지하는 건물을 건설할 예정이라고 한다면,
이 건물은 2개 구획을 차지한다고 도시계획 담당자에게 알려줄 필요가 있습니다.
C/C++에는 int 라는 자료형이 있습니다.
이는 integer(정수)를 의미하면서, 4 byte 의 공간을 필요로 한다는 정의를 갖습니다.
미리 정의된 자료형
C 에서는 몇 가지 자료형을 미리 정의하고 있습니다.
이 자료형을 활용 해서 우리는 메모리 상에 원하는 만큼 공간을 예약할 수 있습니다.
미리 정의된 자료형 - 정수형
int Variable;
4byte 의 int 형으로, 4byte 메모리 공간을 묶어 Variable 이름을 붙여준 것입니다.
4byte 는 다시 32bit 이며, 따라서 저 공간에는 -2의 31승 ~ 2의 31승 까지 보관할 수 있습니다.
- 2의 32승이 아닌 이유는 가장 첫 자리 1bit 를 부호(음수,양수)를 표기하는데 사용했기 때문입니다.
- unsigned (unsigned int) 키워드를 사용하면 부호가 없는 변수임을 표기하며, 2의 32승까지 표현할 수 있습니다.
정수형 계열에 속해있는 자료형들은 2의 bit 승수 만큼 표현할 수 있습니다.
미리 정의된 자료형 - 실수형
실수형의 자료형은 조금 다릅니다. 컴퓨터는 Digital 정수만을 다룰 수 있으며, 정수가 아닌 실수를 처리하기는 간단한 일이 아닙니다.
여러분은 Pi 값을 몇 자리까지 암기하실 수 있으십니까? 아마도 많은 길이는 아닐 것입니다.
실수에는 Pi 값 처럼 소숫점 이하가 무한히 뻗어나가는 수가 있으며, 사람에게나 컴퓨터에게나 기록 자원은 무한하지 않습니다.
- 여기서 자원은 메모리에 한정하는게 아니라, 성능 이슈등도 포함합니다.
따라서 실수를 표현할 때는, 많이 사용되는 실수 범위 내에서 유효하도록 하는 것, 다시 말해 근사값을 사용합니다.
파이 값을 표기할때 3.14라는 근사 값을 대신 사용했던 것처럼,
C의 실수 자료형은 자신이 나타낼 수 있는 유효범위의 숫자 내에서 최대한 근사치를 보관할 수 있는 자료형을 사용합니다.
고정 소수점 (Fixed Point Number)
소숫점을 기준으로 정수부와 소수부를 나누어 사용하는 방식을 생각해 볼 수 있습니다.
만일 우리가 32bit 의 float 형을 소수부와 정수부로 절반씩 나누어 16bit 씩 할당하면
정수부에 2의 16승만큼, 소수부에 2의 16승만큼을 표현할 수 있습니다.
그러나 1.234567890이라는 수나, 1234567890.1이라는 수가 있다면 이 방법으로는 계산을 할 수 없습니다.
- 2의 16승은 65536 입니다.
이러한 실수 표현법은 효율이 좋지 않아 자주 사용하지 않지만, 때때로 정확도가 중요한 곳에서 사용되기도 합니다.
부동 소수점 (Floating Point Number)
실수형에 얼마 만큼의 정수, 얼마 만큼의 소수가 들어올 지 알 수 없기에, 자원을 최대한 활용하는 기법으로 '부동 소수점' 을 사용합니다.
실수는 지수부와 가수부로 나눌 수 있습니다.
- 123.456을 지수부와 가수부로 나누다면, 1.23456 * 10의 2승
- 지수부 10의 2승과 가수부 1.23456으로 나눠 쓸 수 있음
- 지수부에 2, 가수부에 123456 표현.
C 언어에서 사용하는 부동소수점은 IEEE 754 표준을 따릅니다.
float 의 경우 부호에 1bit, 지수부에 8bit, 가수부에 23bit 를 배정합니다.
여기서 지수부는 excess 127코드를 사용합니다.
- 예) 2의 0승은 0111111 127, 2의 1승은 1000000 128
실제 float 는 2진수를 사용하며, 가수부 * 2^(지수부)의 값을 가집니다.
이와 동시에 가장 왼쪽의 수는 무조건 1을 가지게 되므로, 가수부에서 생략합니다.
- 2진수에서 0을 제외한 모든 수는 정규화 했을때 1.xxx의 형태가 됩니다.
#include <stdio.h>
int main(int argc,char** argv)
{
float Var = 4.0;
unsigned char* VarToByte = (unsigned char*)&Var;
unsigned char BinaryStringArray[33];
int i;
for(i=7 ; i>=0 ; i--)
{
BinaryStringArray[i] = VarToByte[3] %2 +'0';
BinaryStringArray[i+8] = VarToByte[2] %2 +'0';
BinaryStringArray[i+16] = VarToByte[1] %2 +'0';
BinaryStringArray[i+24] = VarToByte[0] %2 +'0';
VarToByte[3] /=2;
VarToByte[2] /=2;
VarToByte[1] /=2;
VarToByte[0] /=2;
}
BinaryStringArray[32] = NULL;
printf("%s",BinaryStringArray);
}
실제 float 값을 보여드리기 위한 프로그램입니다. 여기서는 그냥 읽고 넘어가셔도 좋고, 한번 실행시켜보는 것도 좋습니다.
- float 을 선언해서 특정한 값(여기서는 4)를 대입합니다.
- VarToByte char 포인터를 캐스팅 했습니다. float 값을 byte 단위로 읽기위한 작업입니다.
- 반복문을 돌면서 각 byte 를 2진수 문자열로 변환합니다.
little endian 이기 때문에 바이너리값을 보기 편하게 하기 위해 byte 순서를 거꾸로 읽습니다.
01000000100000000000000000000000
0 / 10000001 / 00000000000000000000000로 나눠 읽을 수 있으며,
부호는 0이므로 양수, 지수부는 excess 127코드로 의미하는 값은 2입니다.
가수부는 0이지만, 첫자리 1이 생략된 값이므로 1.0000.. 이 됩니다. 1.0에 2의 2승이므로 2자리를 쉬프트 하면 100.0은 10진수 4와 동일합니다.
01000001010000000000000000000000
위 값은 십진수 12를 표현한 값입니다.
0 / 10000010 / 10000000000000000000000로 나눠 읽을 수 있으며, 1.1에 2의 3승이므로 3자리를 쉬프트 하면 1100.0은 10진수 12와 동일합니다.
그 외의 자료형
조금 특별한 형태의 자료형으로 void 및 포인터가 있습니다.
void
void 는 아무것도 없음을 의미합니다. 아무런 메모리를 할당하지도 않으며 이 자료형으로 빈 공간을 선언할 수도 없습니다. 이 자료형은 문법의 형태를 유지하는데 이용되거나 다른 기법들에 사용됩니다.
예를 들어, 영어에서 진주어와 가주어의 형태가 있습니다. 가주어 it은 별다른 의미를 가지지 않지만, 문법상의 주어 자리를 채우기 위해 사용합니다. void 는 해당 사용법과 유사합니다.
pointer
포인터는 메모리의 주소값을 담는 자료형으로, 시스템의 메모리 주소를 담을 수 있는 크기를 가집니다.
- 32bit 주소 시스템을 사용한다면, 32bit 를 담는 4byte 의 크기를 가집니다.
- 64bit 주소 시스템을 사용한다면, 64bit 를 담는 8byte 의 크기를 가집니다.
class, struct
struct 혹은 C++ 의 class 를 통해 기존의 자료형들을 모아 새로운 자료형을 선언할 수 있습니다.