# 이번 글이 많이 늦어진 점 죄송합니다. 최대한 하루에 한 개 씩 올리자는 것을 목표로 올리도록 하겠습니다.(방학 현장실습 - (이것 또한 현장실습 나가서 공부합니다. 이에 대한 내용은 추후 포스팅 하도록 하겠습니다.) 방학 현장실습으로 인하여 중간 중간 포스팅이 되지 않는 날이 있을 수도 있다는 점 양해의 말씀 드립니다.)

# 또한 이번 글의 내용이 상당히 긴 점 양해의 말씀 드립니다. 내용이 중간에 한 박자 쉬어가게 되면 이해가 안 되는 부분들이 있어서 이렇게 올리게 되었습니다. (정확하고 이해하기 쉽게 설명할 수 있도록 표현을 최대한 다양하게 하겠습니다.)



이번에는 C언어의 상수와 기본 자료형에 대하여 알아 보겠습니다.


1. 자료형


자료형은 데이터를 표현하는 방법입니다.


C언어가 제공해주는 기본 자료형에 대하여 알아 보겠습니다.


int, double, char 등 이와 같은 일부의 키워드를 자료형이라고 합니다.


이러한 자료형들은 다음과 같이 2가지 정보를 담고 있습니다.


1) 표현 또는 저장 하려는 데이터가 '정수' 인지 '실수' 인지에 따른 정보가 담겨 있습니다.


2) 표현하려는 데이터의 크기가 몇 bytes 인지에 대한 정보가 담겨 있습니다.


ex) 1) int 자료형 : '정수'를 표현 및 저장하고, 그 크기는 4 bytes !

     2) double 자료형 : '실수'를 표현 및 저장하고, 그 크기는 8 bytes !




2. 기본 자료형의 종류와 데이터의 표현범위


C언어에서는 총 8개의 기본 자료형을 제공합니다.


다음은 기본 자료형의 종류와 데이터의 표현범위 입니다.


자료형

크기 

값의 표현범위 

정수형 

  char 

 1 Byte

  -128 이상   +127 이하

  short 

 2 Bytes 

  -32,768 이상   +32,767 이하 

  int 

 4 Bytes 

  -2,147,483,684 이상   +2,147,483,647 이하

  long 

 4 ~ 8 Bytes 

  -2,147,483,684 이상   +2,147,483,647 이하

  long long 

 8 Bytes 이상 

  -9,223,372,036,854,775,808 이상

  +9,223,372,036,854,775,807이하

실수형

  float 

 4 Bytes 

  이상  이하

  double 

 8 Bytes 

  이상 이하

  long double 

 8 Bytes 이상 

  double 이상의 표현 범위




자료형 별 크기는 컴파일러(사람이 프로그래밍 언어로 작성한 것을 CPU가 이해 할 수 있도록 변환 해주는 것)에 따라서 약간의 차이를 보입니다.

- C언어의 표준에서는 자료형별 상대적 크기를 표준화 할 뿐 구체적인 크기까지 언급하지는 않습니다.


자료형이 여러개가 있지만 그러한 자료형들이 크게 '정수형''실수형'으로 나누어집니다.

- 데이터를 표현하는 방식이 정수형과 실수형 두 가지로 나누어지기 때문입니다.


정수형에서도, 실수형에서도 둘 이상의 기본 자료형이 존재합니다.

- 표현하고자 하는 값의 크기에 따라서 적절히 선택할 수 있도록 다수의 자료형이 제공되기 때문입니다.


* ex) 3 Bytes로 데이터를 표현 하고 싶은 경우가 있을 수 있습니다. 하지만 그런 경우는(현재 VC++2015 기준) 제공되는 자료형이 3 Bytes는 없기 때문에 불가능합니다.




3. 연산자 sizeof를 이용한 'Byte' 크기의 확인


sizeof 연산자의 피연산자로는 '변수', '상수''자료형의 이름' 등이 올 수 있습니다.



이처럼 sizeof 연산자를 이용하여 자료형의 이름 및 상수, 변수의 크기를 확인 할 수 있습니다.


소괄호 ( ) 는 int와 같은 자료형의 이름에만 필수 입니다. 하지만 모든 피연산자를 대상으로 소괄호를 감싸주는 것이 일반적입니다. (일관성을 가지게 되면 가독성이 좋아지고, 이해하기 쉬워지기 때문입니다.)




4. 정수의 표현 및 처리를 위한 일반적 자료형 선택


일반적으로 정수를 표현 및 처리 하기 위해서 선택되는 자료형은 int 입니다.

- CPU가 연산하기에 가장 적합한 데이터의 크기가 int형의 크기로 결정되기 때문입니다. (운영체제 32 bit / 64 bit 라는 말은 해당 운영체제가 몇 bit 단위로 데이터 처리가 되는지를 말합니다. 따라서 컴퓨팅 환경이 좋아졌기 때문에 int형으로 표현 및 처리 해도 부담이 되지 않기 때문입니다.)

- 연산이 동반이 되면 int형으로 형 변환이 되어서 연산이 진행됩니다.

- 따라서 연산을 동반하는 변수의 선언을 위해서는 int로 선언하는 것이 적합합니다.


* char형, short형 변수는 필요하지 않나? 라는 의문이 생길 수 있습니다.

  - 연산을 수반하지 않으면서(최소한의 연산만 요구가 되면서) 많은 수의 데이터를 저장해야 하고, 그 데이터의 크기가 char 또는 short로 충분히 표현 가능할 경우, char 또는 short로 데이터를 표현 및 저장하는 것이 적절합니다.


다음으로 char 또는 short의 연산을 하게 되는 경우에 대해서 알아 보겠습니다. 글의 후반부에 설명할 내용이지만 형 변환에 대해서 char형과 short형의 연산과 관련된 자료형 선택에 관한 내용이 나온 관계로 char형 과 short형의 연산을 이용해서 간단하게 알아보도록 하겠습니다.



예제에서 확인 할 수 있듯이 char형 변수 num1 = 1 과 num2 = 2의 연산 결과로 3이 되어서 3이라는 값 또한 크기가 char형에 충분히 들어 가기 때문에 sizeof 연산으로 1 Byte 라는 값이 나와야 하는데 4 Bytes로 나온 이유는 결론 부터 말씀드리면 CPU가 정수형 연산을 하기에 가장 적합한 크기가 int 형이기 때문입니다. 따라서 '연산이 되는 동안'에는 1 + 2 해서 나온 결과 값이 3이어도 4 Bytes 로 되어 있고, 3이라는 결과 값을 저장하는 char 형 변수인 result1에 4 Bytes 의 3이 1 Byte로 '자동 형 변환' 하여 저장이 됩니다.


따라서 정수의 표현 및 처리의 일반적인 자료형의 선택은 int형인 것을 알 수 있습니다.




5. 실수의 표현 및 처리를 위한 일반적 자료형 선택


실수 자료형의 선택기준은 '정밀도' 입니다.


저번 글에서 말씀 드렸던 데이터의 표현 방식에 있어서 실수를 완벽하게 표현 할 수 있는 컴퓨팅 환경은 현재로써는 존재하지 않는다는 말씀을 드렸습니다.


따라서 실수 표현 및 처리를 위한 자료형의 선택은 정수 자료형의 선택과 다르게 오차가 되도록 없는 '정밀도' 를 기준으로 실수의 자료형을 선택하게 됩니다.


- 실수의 표현범위는 float, double 둘 다 충분히 넓습니다.

- 하지만 8 Bytes 크기의 double이 float보다 더욱 정밀하게 실수를 표현합니다.

* long double은 컴퓨터가 너무 큰 Bytes 이다보니 그 크기가 부담 스럽기 때문에 double을 일반적으로 선택합니다.


- 컴퓨팅 환경의 발전으로 float 보다 정밀도가 높은 double형이 데이터의 표현 및 연산이 덜 부담스럽습니다.

- float형 데이터의 경우 정밀도가 부족한 경우가 많습니다.




위의 두 가지 예제에서 확인 할 수 있듯이 float형은 데이터 표현의 정밀도가 낮아서 발생한 오차의 누적으로 소숫점 6 번 째 자리에서 2라는 값이 출력이 되고, double 형의 경우 float 형 보다 데이터 표현의 정밀도가 높아서 소숫점 6 번 째 자리에서 0이라는 값이 출력이 되는 것을 확인 할 수 있습니다.


이러한 예제의 결과를 바탕으로 알 수 있는 사실은 'double 형''float 형' 보다 정밀도가 높다! 라는 사실을 알 수 있습니다.


다음은 실수 자료형의 소수점 이하 정밀도와 바이트수를 나타낸 표 입니다.


실수 자료형 

소수점 이하 정밀도 

바이트 수 

    float 

    6자리 

    4 

    double 

    15자리 

    8 

    long double 

    18자리 

    12 


* double형 변수의 '출력' 에 사용되는 서식문자는 %f    ㅡㅡ> printf

  double형 변수의 '입력' 에 사용되는 서식문자는 %lf   ㅡㅡ> scanf


* double 형 변수의 '출력'은 %f 인데 '입력'은 왜 %lf 를 사용하지? 라는 궁금증을 가지시는 분들이 계실 텐데 이에 대한 내용은 다음 글에서 다루게 될 printf함수와 scanf함수에 대하여 간단하게 정리하면서 알아보도록 하겠습니다.




6. 정수형의 앞에 unsigned를 붙여서 0과 양의 정수만 표현


6 번 째 제목처럼 int, char, short, long, long long의 앞에 unsigned를 붙여서 0과 양의 정수만을 표현 하는 방법입니다.


다음의 unsigned가 붙지 않은 정수 자료형의 보편적인 크기와 unsigned 선언을 포함하는 정수 자료형의 보편적인 크기를 나타내는 표를 보겠습니다.


정수 자료형 

크기 

값의 표현범위 

    char 

    1 Byte

  -128이상 +127이하

    unsigned char 

  0이상 255이하

    short 

    2 Bytes 

  -32,768이상 +32,767이하

    unsigned short 

  0이상 65535이하

    int 

    4 Bytes 

  -2,147,483,648이상 + 2,147,483,647이하

    unsigned int 

  0이상 4,294,967,295이하

    long 

    4 Bytes 

  -2,147,483,648이상 + 2,147,483,647이하

    unsigned long 

  0이상 4,294,967,295이하

    long long 

    8 Bytes 

  -9,223,372,036,854,775,808이상      +9,223,372,036,854,775,807이하

    unsigned long long 

  0이상 18,446,744,073,709,551,615이하


표를 통하여 다음과 같은 사실들을 알 수 있습니다.

- 정수 자료형의 이름 앞에는 unsigned 선언을 붙일 수 있습니다.

- unsigned가 붙으면, MSB(부호 비트)도 데이터의 크기를 표현하는데 사용이 됩니다.

- 따라서 표현하는 값의 범위가 양의 정수로 제한이 되며 양의 정수로 두 배 늘어나게 됩니다.




7. 문자의 표현을 위한 약속, 아스키(ASCII) 코드


이번 7번 째 주제에서는 영어를 기준으로 하겠습니다.(컴퓨터가의 언어 표현을 영어로 먼저 표기 했기 때문입니다. 또한 아스키 코드는 자주 사용하게 됩니다.)


아스키 코드는 미국 표준 협회(ANSI: American National Standards Instute)에 의해서 제정된 '아스키(ASCII: American Standard Code Code for Information Interchange) 코드' 입니다.

- 컴퓨터는 문자를 표현 및 저장하지 못 합니다. 따라서 문자의 표현을 목적으로 각 문자에 고유한 숫자를 지정합니다.

- 인간이 입력하는 문자는 해당 문자의 숫자로 변환이 되어 컴퓨터에 저장 및 인식이 되고, 컴퓨터에 저장된 숫자는 문자로 변환이 되어 인간의 눈에 보여지게 됩니다.


따라서 실제로 컴퓨터에게 전달이 되는 데이터는 문자가 아닌 숫자입니다.


본격적으로 문자 표현에 대해 알아보기 전, ASCII 코드 표를 보고 진행 하도록 하겠습니다.



<출처 : Google 검색>


(ASCII 코드에 대해서 검색을 하게 될 경우 굉장히 많은 자료들이 존재 합니다. ASCII 코드에 관심이 있거나 필요하신 분들은 인터넷 상에 자료들이 많으니 검색을 통해 알아 보시기 바랍니다.)


미국 표준 협회에서 지정한 1 Byte 로 표현이 가능한 128개의 문자표 입니다.


소스를 작성 후 컴파일 시 각 문자는 해당 아스키 코드 값으로 변환이 됩니다.


C 프로그램 상에서 문자는 작은 따옴표('')로 묶어서 표현 합니다.



여기서 드는 의문점이 있습니다.


문자는 왜 char형 변수에 저장을 할까? 라는 의문입니다.


이유는 char형 변수가 문자열을 저장하기 위해 디자인 된 자료형이기 때문입니다.


문자는 연산을 동반하지 않습니다.


문자는 저장하고 보기 위한 것입니다.


또한 문자는 연산 보다 '문자열' 처럼 많은 양의 데이터가 대부분이기 때문에 부담이 되지 않는 char형 (1 byte) 변수를 사용합니다.


이렇듯, 문자 저장의 측명에서 보면 char형 자료형이 의미가 있게 됩니다.


결론적으로 문자를 저장하기 위해 특화된 정수 자료형이 char형 자료형 입니다.




8. 문자의 표현


서식문자 %c : 해당 숫자의 아스키 코드 문자를 출력하라는 의미입니다.


다음은 문자를 char형 변수에 저장하는 이유 입니다.

- 모든 아스키 코드 문자는 1 Byte로 충분히 표현 가능합니다.(ASCII 코드가 1 Byte로 표현 가능하도록 만들어 졌기 때문입니다.)

- 문자는 덧셈, 뺄셈과 같은 연산을 동반하지 않습니다. 단지 '표현' 에 사용될 뿐입니다.

- 따라서 1 Byte 크기인 char형 변수가 문자를 저장하기에 최적의 장소가 됩니다.

* 문자는 int형 변수에도 저장이 가능합니다 ! 문자라는 것은 사람이 보는 것이고, 실제로 문자에 해당하는 값은 '수' 이기 때문입니다.




9. 상수에 대한 기본적인 이해


int num = 3 + 2; 라고 했을 경우 3과 2도 메모리 공간이 필요합니다. 이유는 CPU에서 연산이 되기 위해서는 변수인 num 뿐만 아니라 3과 2도 메모리 공간이 필요하기 때문입니다.


C언어는 컴파일에 있어서 기본 자료형을 근거로 합니다.


C컴파일러는 써 놓은 숫자를 int형으로 표현을 해서 메모리 공간에 저장합니다.


그렇다면 8번 째 주제에서 문자는 사람이 보기 편하게 하기 위해 '표현'을 한 것일 뿐이고, 실제로 문자에 해당하는 값은 '수'라는 말씀을 드렸습니다.


그러면 4번 째 주제에서 말씀 드렸던 변수에 저장되기 전의 문자는 몇 Bytes 일까? 라는 의문을 가질 수 있게 됩니다. 이에 대한 내용은 다음의 예제를 보고 확인 하겠습니다.



예제에서 확인한 결과 문자라고 생각했던 'A'의 크기가 sizeof 연산에 의해 4 Bytes인 int형 인 것을 알 수 있습니다. 이 또한 변수에 저장 될 경우 형 변환이 이루어지게 됩니다. ( 또한 위의 예제는 이 글의 후반부에 다루게 될 리터럴 상수와 관련된 예제입니다. 이는 뒤쪽에서 다시 설명 드리겠습니다.)




10. 이름을 지니지 않는 리터럴 상수와 리터럴 상수의 자료형


이번에 다루게 될 내용은 이름을 지니지 않는 리터럴 상수 입니다.


연산을 위해서는 30, 40과 같이 프로그램상에 표현되는 상수(숫자)도 '메모리 공간에 저장되어야 합니다.'


글의 초반부에 사용했던 예제를 통해 알아 보도록 하겠습니다.



위의 예제를 통해 알 수 있는 사실은 여러가지가 있습니다.


1) 1, 2, 300, 400 처럼 저장되는 값은 이름이 존재하지 않습니다. (num1 이라는 '이름'의 변수가 '1'이라는 값을 가지고 있는 것입니다. '1'은 이름이 없습니다. 이렇듯 이름이 존재하지 않으니 변경이 불가능한 상수(리터럴 상수) 입니다.)

2) 뜬금 없이 1, 2, 300, 400 처럼 값을 주게 되면 CPU의 연산 대상이 되지 않습니다. 그러므로 메모리 공간에 저장이 되어야 합니다.

3) 글의 최후반부에 다루게 될 형변환에 대한 것을 알 수 있습니다.


이러한 내용을 바탕으로 리터럴 상수도 메모리 공간에 저장이 되어야 한다는 사실을 이해해 보면,  5 번째 줄의 문장 내용이 '정수를 표현 하고, 그 크기는 1 Byte로 하는 변수 인 num1과 num2, result1을 선언할게, 각각의 변수 num1과 num2에 저장될 값은 1과 2야. 그리고 선언한 num1과 num2의 + 연산을 통해서 나온 결과를 result1이라는 이름을 가진 변수에 저장할게.' 라는 내용이 되는 것을 알 수 있습니다.


또한 5 번 째 줄의 연산 과정에 있어서 변수인 num1과 num2가 연산이 되는 것이 아닌, num1과 num2에 저장 되어 있는 1과 2가 연산이 되는 것이므로 1과 2는 CPU가 연산하기 편한 int형으로 변환이 된 후 연산을 하고 해당 연산의 결과 값 또한 int형이 되어서 4 Bytes가 되지만 그 결과 값을 1 Byte의 char형 변수인 result1에 저장하는 것이기 때문에 4 Bytes의 결과 값이 1 Byte 로 형변환이 되어 저장이 됩니다.


이렇듯 변수에 저장되는 값이 처음부터 변수의 자료형에 맞춰서 저장이 되는 것이 아닌 먼저 상수에 대한 값을 저장할 메모리 공간이 필요하게 됩니다. 이는 연산과정에서도 마찬가지 입니다.


따라서 변수 선언 및 연산과정에 있어서 상수는 메모리 공간에 할당이 되어진 후 연산 및 변수에 저장이 진행이 되게 됩니다.

* int num = 3 + 4; 라는 문장을 작성한 경우 3과 4가 그대로 메모리에 남아 있어서 걱정인데 어떻게 하지? 라는 궁금증이 생기실 수 있습니다. 하지만 3과 4의 연산이 진행되고, 결과 값이 나올 때까지만 메모리 공간에 할당이 되어 있고, 변수 저장 및 다음 행으로 넘어가게 될 경우 메모리 공간에서 3과 4의 값은 증발하게 됩니다. 어차피 이름이 존재하지 않아서 접근 할 수 없는 값이기 때문입니다.


이와 같은 내용들을 바탕으로 리터럴 상수의 자료형이 결정되는 것 또한 알 수 있습니다.



위쪽에서 사용했던 예제를 다시 한 번 사용했습니다.


이번 예제에서는 리터럴 상수가 변수에 저장되기 전, 단순히 상수의 값을 어떤 자료형으로 지정해서 메모리 공간에 할당하는지 알아보기에 아주 간단한 예제 입니다.


7은 정수형 리터럴 상수이므로 int형으로 할당이 된 것을 확인 할 수 있습니다.


7.14는 실수형 리터럴 상수이므로 double형으로 할당이 된 것을 확인 할 수 있습니다.


문자 'A'는 실질적으로 문자가 아닌 숫자 값입니다. 아스키 코드표의 65는 'A'라는 문자와 매칭이 됩니다. 따라서 65는 정수형 리터럴 상수이므로 int형으로 할당이 된 것을 확인 할 수 있습니다.




11. 접미사를 이용한 다양한 상수의 표현


정수를 표현 할 때는 int, 실수를 표현할 때는 double입니다. 그 이외의 자료형을 가지고 상수를 표현하고 싶을 때 사용하는 것이 '접미사'입니다.


이러한 접미사들은 대,소문자를 구분하지 않습니다.


L이 붙으면 정수 형이고, 실수형에 붙으면 double long형입니다.


접미사를 통해서 상수의 자료형을 변경할 수 있습니다.


또한 다음과 같은 경우에는 에러가 발생합니다. 이러한 경우 접미사를 붙여서 사용하게 되면 에러가 발생하지 않습니다.


ex) float num1 = 5.789;

이 문장은 경고메시지가 발생하게 됩니다.

실수의 기본 자료형은 double형인데 그보다 표현 범위가 적은 float형 자료형을 사용하게 되면 데이터의 손실이 있을 거라는 경고메시지가 출력 됩니다.


이러한 경우 다음과 같이 접미사를 통해서 상수의 자료형을 변경하면 에러가 발생하지 않습니다.


ex) float num1 = 5.789f;

     float num2 = 3.24F + 5.12F;    (소문자 f 대신 대문자 F를 써도 됩니다.)


다음은 정수형 상수의 표현을 위한 접미사와 실수형 상수의 표현을 위한 접미사를 나타낸 표입니다.


접미사 

자료형 

사용의 예 

  U 

  unsigned int 

  unsigned int n = 1025U 

  L 

  long 

  long n = 2467L 

  UL 

  unsigned long 

  unsigned long n = 3456UL 

  LL 

  long long 

  long long n = 5768LL 

  ULL 

  unsigned long long 

  unsigned long long n = 8979ULL 


[정수형 상수의 표현을 위한 접미사]





접미사 

자료형 

사용의 예 

  F 

  float 

  float f = 3.15F 

  L 

  long double 

  long double f = 5.789L 


[실수형 상수의 표현을 위한 접미사]




12. 이름을 지니는 심볼릭(Symbolic) 상수: const 상수


글의 위쪽 내용 중 리터럴 상수는 이름이 존재하지 않아서 접근이 불가능 하다는 말씀을 드렸습니다.


하지만 이름을 지니는 심볼릭 상수라는 것도 존재 합니다.


심볼릭 상수를 선언 해주려면 변수 선언 문장의 맨 앞에 const라는 선언을 붙여줘야 합니다.

ex) const int MAX=100;    ㅡㅡ>   MAX라는 이름의 변수를 상수로 선언하겠다는 의미입니다.


const라는 것은 'const를 써서 해당 변수를 상수처럼 썼으면 좋겠다' 이러한 경우에 사용하게 됩니다.


const는 컴파일러가 인지하는 상수입니다.(리터럴 상수처럼 일시적으로 메모리 공간에 할당 되었다가 이름이 존재하지 않고, 의미가 없어져서 사라져 버리는 그러한 상수가 아닌 상수입니다.)


const는 변수를 상수화 시키는 키워드입니다.


const 상수는 메모리 공간에 할당되는 상수가 아닙니다.  const int MAX=100; 에서 100이라는 값이 const int MAX라는 변수에 할당 되기 위해 메모리 공간에 일시적으로 할당이 될지는 몰라도 MAX라는 변수에 할당이 되고 난 후에는 MAX라는 변수 자체가 100이라는 상수가 되기 때문입니다.


이러한 상수화된(const상수) 변수의 값을 변경하려 할 시 에러가 발생합니다. (개인적으로 포인터로 메모리에 직접 접근을 하게 될 경우 가능 할 것 같다는생각이 듭니다. 확실한 것은 아니고, 추후 포인터를 다루면서 제대로 알아보도록 하겠습니다.)



13. 자료형의 변환


이번에 다루게 될 내용은 자료형의 변환입니다.


여기까지 이해하시면서 잘 따라와 주셨으면 자료형의 변환에 대하여 어느정도 이해 하셨을거라 생각이 됩니다.


단순하게 'int형을 double형으로 바꿔야겠다. int inum=4; 를 double형으로 4.0으로 바꿔야지.'라고 생각하셔도 틀린 것은 아닙니다.


다만 저러한 형식으로 이해를 하시게 되면 정수와 실수 사이의 형변환에 있어서 정수형의 표현방식, 실수형의 표현방식에 있어서 문제가 발생하게 됩니다.


그렇다면 형변환을 어떻게 이해하면 좋을까? 라는 생각을 해보겠습니다.


정수형으로 선언된 자료의 '비트열'을 실수형 자료의 '비트열'로 다시 구성하자 라는 식으로 이해를 하시면 정수형과 실수형의 표현방식에 있어서 발생하는 문제가 줄어든다(?) 라고 생각하시면 되겠습니다.


실수의 표현 방식은 데이터의 표현방식이라는 글에서 제대로 다루지 않았지만 4 Bytes를 기준으로 앞의 반절은 소수점 이상부분을 표현하고, 뒤의 반절은 소수점 이하부분을 2진수 0000 0000 0000 0101 . 0000 0000 0000 1010 이런식으로 표현하면 되지 않을까? 라는 생각을 하실 수 있습니다.


하지만 이러한 경우 오차도 엄청 많이나게 되고, 표현 할 수 있는 범위도 줄어들게 됩니다. 따라서 실수의 표현방식을 오차도 적고, 표현 범위도 적게 하는 가장 보편적인 기본화 되어 있는 공식을 사용하여 구성하게 되어 있습니다.(실수 표현 방식의 기본화 되어 있는 공식은 인터넷상에 많은 자료가 존재 합니다. 궁금하시거나 관심 있으신 분들은 인터넷 검색을 해보시는 것을 권장합니다.)


이렇듯 정수형과 실수형간의 형변환에 있어서 굉장히 작은 값인 1, 3 이러한 값들일 경우 표현하는데 어려움이 없겠지만 값들이 굉장히 커지게 되면 정수형과 실수형의 표현방식의 차이로 인하여 형변환 하는데에 어려움이 따르게 됩니다.


따라서 컴퓨터는 형변환을 하게 될 경우 실수형에서 정수형으로 형변환을 한다는 의미는 실수형 표현방식으로 표현이 되어 있는 값의 2진수 비트열을 정수형 표현 방식의 2진수 비트열로 재구성 하는 것을 의미 합니다.


또한 자료형의 변환 시 오차 발생, 데이터 손실이 생길 수 있습니다.

ex) 실수형 4.123을 정수형으로 형변환 하게되면 프로그래밍 환경에서 정수라는 것은 소수점을 포함하지 않은 음의 정수, 0, 양의 정수만을 의미하기 때문에 변환 시 소수점 이하 .123은 다 버려지게 되고, 4 라는 값으로 형변환이 되게 됩니다. 이때 .123이라는 데이터의 손실이 발생하게 됩니다.


자료형의 변환의 종류는 크게 2가지로 존재 합니다.

1) 자동 형 변환

2) 명시적 형 변환 : 강제로 변환 시킵니다.


자동 형 변환 중 하나인 대입연산의 전달과정에서 발생하는 자동 형 변환을 다음 예제를 통해 확인 하겠습니다.



위의 예제는 피연산자의 자료형 불일치로 발생하는 자동 형 변환을 나타내는 예제입니다.


이렇듯 앞서 설명한 오차 발생, 데이터 손실, 대입 연산시 발생하는 형변환에 대한 내용들을 확인 할 수 있습니다.


또한 다음의 자동 형 변환 규칙을 근거로 int형 데이터 245가 double형 데이터 245.000000으로 형 변환이 되어 변수에 저장 되는 것을 확인 할 수 있습니다.

int    ㅡ>    long    ㅡ>    long long    ㅡ>    float    ㅡ>    double    ㅡ>    long double


* - 산술 연산에서의 자동 형 변환 규칙

  - 바이트 크기가 큰 자료형이 우선시 됩니다. (정수형, 실수형 각각의 형에서는 바이트 크기가 큰 자료형이 우선시 됩니다.)

  - 정수형보다 실수형을 우선시 합니다.(정수 자료형을 실수 자료형으로 형 변환을 하게 되면 데이터 손실이 현저하게 줄어들기 때문입니다.)

  - 이러한 규칙은 데이터의 손실을 최소화 하기 위한 기준입니다.


또다른 자동 형 변환 중 하나인 정수의 승격에 의한 자동 형 변환이 있습니다.


다음은 정수의 승격에 의한 자동 형변환 예제 입니다.(앞서 사용한 예제를 다시 사용하겠습니다.)



위의 예제에서 확인 할 수 있듯이 정수의 승격에 의한 자동 형변환이라는 것은 일반적으로 CPU가 처리하기에 가장 적합한 크기의 정수 자료형을 int로 정의하는 것을 말합니다.



마지막으로 자료형의 형 변환의 종류 중 다른 하나인 명시적형 변환(강제로 일으키는 형 변환) 에 대하여 알아 보겠습니다.


우선 명시적형 변환을 설명하기에 앞서 예제를 먼저 본 후 설명을 진행하도록 하겠습니다.



일반적으로 사람이 생각 할 때, '3/4=0.75 가 나오겠지?' 라는 생각을 하게 됩니다. 하지만 결과를 보면 0.000000이 출력되는 것을 확인 할 수 있습니다.


앞서 작성했던 글 중, 변수와 연산자 부분에서 연산기호의 우선순위 부분이 있었습니다.


이 때, 산술연산등이 먼저 진행이 되고, 대입연산이 진행이 되었습니다. 이러한 점을 바탕으로 double형 변수 divResult에 값이 저장 되기전, num1 / num2의 자료형이 int형인 상태에서 연산이 진행이 됩니다. 그렇게 되면 프로그래밍에서 정수 3과 정수 4를 나누면 몫은 0이 됩니다. 따라서 연산의 결과 값이 int형 정수인 0이 됩니다.


int형 정수인 0을 double형 변수인 divResult에 저장을 할 때 0을 실수로 형 변환 해도 0.000000이 됩니다. 따라서 divResult에는 0.000000이라는 값이 저장이 되는 것 입니다.


이러한 것을 해결 해주는 방법이 바로 명시적 형 변환(사용자가 직접! 형 변환을 선.언 해준다!)입니다.


위의 예제사진의 소스코드를 다음과 같이 변경 해주면 됩니다.


7번째 줄의 divResult = num1 / num2;를  divResult = (double)num1/ num2; 또는 divResult = num1 / (double)num2; 라는 형식의 문장으로 변경 해주게 되면 연산자의 우선순위에 근거하여 연산이 이루어지기전 num1 또는 num2의 형변환이 이루어지게 되고, 정수의 승격에 의한 자동 형변환에 의하여 남은 정수형 변수가 double 형으로 변환이 되어서 double형 자료형간의 연산이 이루어 지게 됩니다.


그렇게 되면 3.0 / 4.0 이라는 연산을 하게 되는데 이 때 나오는 결과는 0.75로 double형 자료형의 결과가 나오게 됩니다.



이것으로 이번 글의 내용인 상수와 기본 자료형에 대하여 알아 보았습니다.


내용에 대하여 제대로 설명을 못 한 점도 있고, 내용 자체가 (저도) 이해하기 약간 난해한 점도 있어서 이해가 제대로 되지 않으신 분들도 계실 겁니다.


이러한 부분은 추후 포인터와 메모리 부분을 다루면서 보다 정확하게 설명하겠습니다.






다음에는 printf함수와 scanf함수 에 대하여 공부하고, 글을 올리도록 하겠습니다.








'프로그래밍 언어 > C' 카테고리의 다른 글

C언어 반복문 - while문(1)  (0) 2017.01.02
C언어 printf 함수 와 scanf 함수  (0) 2017.01.01
C언어 데이터 표현방식  (0) 2016.12.25
C언어 변수와 연산자  (0) 2016.12.24
C언어 공부 시작  (0) 2016.12.21

이번 글에서는 컴퓨터가 데이터를 표현하는 방식에 대하여 알아 보겠습니다.




1. 컴퓨터가 데이터를 표현하는 방식


컴퓨터는 2진수를 기반으로 데이터를 표현하고 연산도 진행합니다.


2진수 뿐만 아니라 10진수, 8진수, 16진수등 N진수 형식으로 데이터를 표현 합니다.

(물론 실제로는 2진수 (0 과 1) 로 모든 것을 처리 합니다 !)


- 2진수 : 두 개의 기호(1, 0)를 이용해서 값(데이터)을 표현하는 방식입니다.


- 10진수 : 열 개의 기호(0~9)를 이용해서 값(데이터)을 표현하는 방식입니다.


- 8진수 : 여덟 개의 기호(0~7)를 이용해서 값(데이터)을 표현하는 방식입니다.


- 16진수 : 열 여섯 개의 기호(0~9, A~F)를 이용해서 값(데이터)을 표현하는 방식입니다.


- N진수 : N개의 기호를 이용해서 값(데이터)을 표현하는 방식입니다.




2. 데이터의 표현단위인 비트(Bit)와 바이트(Byte)


1 Bit = 0 또는 1이라는 정보 '하나'를 저장 할 수 있는 저장공간을 의미합니다. 또한 컴퓨터의 데이터 처리 단위의 최소 단위 이기도 합니다.


1 Byte = 8개의 Bits ( 8 bits )로 이루어져 있는데, 1 Byte를 언급한 이유는 프로그램에서 의미 있는 데이터를 표현하는데 있어서 가장 기본이 되는 단위가 Byte이기 때문입니다.




3. 정수와 실수의 표현 방식


1) 정수의 표현 방식

    - 1 Byte를 기준으로 가장 왼쪽의 1 bit가 부호를 나타내는 비트(부호비트) 입니다.

    - ex) 1 0 0 0  0 0 0 1    ->    가장 왼쪽의 1 bit가 1일 경우 음수, 0일 경우 양수를 나타냅니다.

    - 부호비트를 제외한 나머지 비트는 크기를 나타내는데 사용됩니다.

    - 음의 정수를 표현 할 때는 2의 보수를 취합니다.

    - 음의 정수를 표현 할 경우 부호비트만 바꾸면 음수라는 실수를 할 수 있게 되는데 이는 간단 예제로 확인 해 보겠습니다.



수학으로 생각해 보겠습니다. 5 - 5 = 0 이 되어야 하는데 컴퓨터의 연산에서는 위의 예제와 같이 할 경우 0이 아니게 되므로 컴퓨터 에서의 음의 정수 표현 방식에 문제가 있다는 것을 알 수 있습니다. 따라서 컴퓨터가 인식하는 음의 정수는 2의 보수 입니다.


2의 보수를 구하는 것은 쉽게 생각하면 됩니다.

해당 값들의 비트 값을 0은 1로, 1은 0으로 반전시켜서 써주면 1의 보수가 됩니다.

이 때 1의 보수에서 +1 을 해주게 되면 2의 보수가 나오게 됩니다.


ex) 0 0 0 0  0 0 1 1     <<     3

  + 1 1 1 1  1 1 0 1     <<    2의 보수

-------------------------

    0 0 0 0  0 0 0 0     <<    결과가 0이 되므로 예제에서의 2의 보수는 -3이 되는 것을 확인 할 수 있습니다.


*  이 때 1이 가장 왼쪽에 있어야 되지 않나?? 9자리가 되지 않나?? 하는 생각을 할 수 있는데, 컴퓨터 연산의 경우 1 Byte + 1 Byte = 1 Byte가 되어야 합니다. 따라서 1 Byte를 넘어서는 값인 1은 버려지는 값이 됩니다. 따라서 남은 값들이 0이 되어서 컴퓨터가 인식하는 음의 정수는 2의 보수 인 것을 알 수 있습니다.




2) 실수의 표현 방식

    - 실수의 표현 방식은 아주 정확하고 깊게 이해 하려는 것이 아닌 컴퓨터의 실수 표현 방식은 정확히 표현을 할 수 없고, 오차가 존재 한다는 것만 알고 가도록 하겠습니다.


ex) 다음은 컴퓨터의 실수 표현의 오차로 인한 오차 누적의 결과로 발생한 실수 표현 방식을 나타낸 결과 입니다.



* 이론적으로 오차 없이 모든 실수를 완벽하게 표현할 능력이 있는 컴퓨팅 환경은 존재하지 않습니다.




4. 비트 연산자


다음으로 비트 연산자에 대하여 알아 보겠습니다.


* 비트 연산자의 경우 앞 쪽의 연산자 부분에서 조금 더 자세히 다루지 않고 데이터 표현 방식에서 다루는 이유는 데이터 표현 방식이 비트 단위 2진수 기반으로 처리가 되기 때문에 이러한 '비트'를 직접적으로 연산하는 비트 연산자를 이번 글에서 다루게 되었습니다.


다음은 비트 연산자의 종류와 기능입니다.


연산자 

연산자의 기능 

결합방향 

비트단위로 AND 연산을 한다.

ex) num1 & num2; 

-> 

비트단위로 OR 연산을 한다.

ex) num1 | num2; 

-> 

비트단위로 XOR 연산을 한다.

ex) num1 ^ num2; 

-> 

단항 연산자로서 피연산자의 모든 비트를 반전시킨다. 

ex) ~num;  // num은 변화 없음, 반전 결과만 반환

<- 

<<

피연산자의 비트 열을 왼쪽으로 이동시킨다.

ex) num << 2;  // num은 변화 없음, 두 칸 왼쪽 이동 결과만 반환

-> 

>> 

피연산자의 비트 열을 오른쪽으로 이동시킨다.

ex) num >> 2;  // num은 변화 없음, 두 칸 오른쪽 이동 결과만 반환 

-> 



1) & 연산자 : 비트단위 AND

   - & 연산은 두 개의 비트가 모두 1일 때 1을 반환하는 연산입니다.


   - 0 & 0    0을 반환

   - 0 & 1    0을 반환

   - 1 & 0    0을 반환

   - 1 & 1    1을 반환




2) | 연산자 : 비트단위 OR

   - | 연산은 두 개의 비트 중 하나라도 1이면 1을 반환하는 연산입니다.


   - 0 | 0    0을 반환

   - 0 | 1    1을 반환

   - 1 | 0    1을 반환

   - 1 | 1    1을 반환




3) ^ 연산자 : 비트단위 XOR

    - ^ 연산은 두 개의 비트가 서로 다른 경우에 1을 반환하는 연산입니다.


    - 0 ^ 0    0을 반환

    - 0 ^ 1    1을 반환

    - 1 ^ 0    1을 반환

    - 1 ^ 1    0을 반환




4) ~ 연산자 : 비트단위 NOT

    - ~연산은 비트를 0에서 1로, 1에서 0으로 반전시키기 때문에 보수연산이라고도 합니다.


    - ~0    1을 반환

    - ~1    0을 반환


    * ~ 연산자는 부호비트 조차 반전시킵니다. ~ 연산자를 사용해 2의 보수를 구하려는 경우 ~연산을 사용한 값에 + 1을 해줘야 2의 보수가 구해집니다.




5) << 연산자 : 비트의 왼쪽 이동(Shift)

    - << 연산자는 두 개의 피연산자를 요구합니다.

    - num1 << num2    num1의 비트 열을 num2칸씩 왼쪽으로 이동시킨 결과를 반환 합니다.

    - 8 << 2    8의 '비트열'을 2칸씩 왼쪽으로 이동시킨 결과를 반환 합니다.


    * 비트의 열을 왼쪽으로 1칸씩 이동시킬 때마다 정수의 값은 두 배가 됩니다. 이를 토대로 반대의 경우 정수의 값은 반절로 나누어 지는 것을 알 수 있습니다.




6) >> 연산자 : 비트의 오른쪽 이동(Shift)

    - >> 연산자와 << 연산자의 가장 큰 차이점은 비트의 열을 이동 시키는 방향에 있습니다.

    - << 연산의 경우 0을 채워넣으면 되니까 상관이 없지만, >> 연산의 경우 양수가 아닌 음수의 비트열을 이동시킬 경우에 음수를 유지 할 것인가, 그렇지 않을 것인가에 따라 나눠지게 됩니다. (이 경우 CPU에 따라 계산 방식의 차이를 보이게 됩니다.)

    - 음수를 유지하는 CPU의 경우 1을 채워 넣고, 그렇지 않은 CPU의 경우 0을 채워 넣게 됩니다.



* 음수를 유지하는 CPU에서의 연산 결과 입니다.





이것으로 데이터 표현방식을 마치도록 하겠습니다.


다음은 상수와 기본 자료형에 대하여 공부하고, 글을 올리도록 하겠습니다.






'프로그래밍 언어 > C' 카테고리의 다른 글

C언어 반복문 - while문(1)  (0) 2017.01.02
C언어 printf 함수 와 scanf 함수  (0) 2017.01.01
C언어 상수와 기본 자료형  (0) 2016.12.27
C언어 변수와 연산자  (0) 2016.12.24
C언어 공부 시작  (0) 2016.12.21

+ Recent posts