글수 49
오류가 있으면 댓글로 바로바로 지적해 주세요...
===================================================
#04.초보가 쓰는 C 언어 강좌
(메모리와 변수)
04.01 메모리에 대해
컴퓨터는 크게 기억장치부분, 연산부분, 입출력부분으로 나눌 수 있습니다. 기억장치는 우선 메모리를 말하며 보조기억 장치로는 하드디스크 CD-ROM 같은 게 있고, 연산장치는 CPU를 말하며 (특히 ALU를 말합니다.) , 입출력부분은 키보드, 모니터처럼 우리가 컴퓨터를 조정하거나 그 결과를 보여주는 부분을 말합니다.
기억장치 중 메모리는 실행코드(프로그램언어를 컴파일 해둔 기계어)를 잠시 그 위에 옮겨둘 수 있고, 실행 결과를 저장할 공간을 제공합니다. 프로그램은 평상시에는 하드디스크 상에 있습니다. 사용자가 그 프로그램을 실행하면 운영체제가 알아서 메모리로 옮겨 주고, 결과를 저장할 공간을 실행프로그램을 봐가면서 메모리에 맞게 마련해 줍니다. 따라서 프로그래머는 이 프로그램은 이 공간이 필요하다고 말하기만 하면 됩니다. 그 때 사용하는 게 자료형이라는 것입니다.
04. 02 기본 자료형(Builtin Data Type)
C언어에서 메모리를 얻기 위해서는 자료에 맞는 메모리를 요구해야 합니다. 자료형(Data Type)은 크게 정수형(Integer), 부동소수형(Floating point), 문자형(Character)으로 나눌 수 있습니다. 정수형은 말 그대로 정수를 다루고, 부동소수형은 실수를 문자형은 문자를 다룹니다. 그리고 그 형은 내부적으로 크기에 따라 또 다시 나누어집니다.
왜, 이렇게 자료형을 나눌까요. 첫째는 메모리를 효율적으로 사용하기 위해서 입니다. 당연히 효율적으로 사용해야 메모리를 적게 사용할 수 있겠죠. 또, 자료에 맞는 연산(계산)을 하기 위해서 입니다. 소수점 계산하는 곳과 정수를 계산하는 곳은 CPU 내에 따로 위치해 있습니다.
04.03 변수(Variable)
수학에서 많이 들었던 낱말입니다. 쉽게 말해 변하는 수입니다. 보통 수학에서 함수를 사용할 때 쓰는 x 같은 문자와 비슷한 개념입니다. 변수는 자료형과 같이 쓰입니다. int a; 처럼. 여기서 a 가 변수입니다. 우리는 a, 대신 다른 이름을 줄 수 있습니다. 바로 앞 강좌에 심볼 이름 붙이는 규칙이 있습니다. 그 규칙에 맞는 여러 이름을 줄 수 있습니다. int a; 처럼 이렇게 변수를 만드는 행위를 변수를 선언한다(declaration) 고 합니다. (정확히 더 따지고 들어가면 선언:declaration와 정의:definition을 명확히 구별해서 사용해야 하겠으나 그러면 처음 배우는 사람들에게는 머리 복잡하니 구별하지 않겠습니다.)
변수가 변하는 수라는 말에 걸맞게 값을 여러가지 넣어 줄 수 있습니다. 당연히 사용하기 전, 맨 마지막에 넣어준 값만 기억하고 있습니다. 그리고 맨 처음 넣어주는 행위를 특별히 초기화 한다고 합니다.
04.04 정수형
정수형에는 int, short, long 이 있습니다. 바로 앞 강좌에 키워드라는 주제를 가진 글에 이 세 가지가 다 있습니다. 여기서 가장 중요한 것은 int 입니다.
Project 를 만들어 다음 예제를 실행해 보세요 (Project 만들 줄 모르신다면 앞의 강좌를 다시 읽어보세요.)
-----------------------------------------------------------------------------
/* 예제 04.01 */
#include <stdio.h>
#include <stdlib.h>
int main()
{
int var; /*1) var 라는 정수형 변수 선언 */
system("PAUSE");
/* Visual C를 사용한다면 이 부분은 없어도 됩니다. */
return 0;
}
-------------------------------------------------------------------------
컴파일 해서 실행하면 아직은 아무것도 안 나옵니다. 여기서 주석 1) 에서 int 형 변수 var 를 정의했습니다. 선언은 공간을 만들어 달라고 컴파일러에게 요구하는 것입니다(정확히는 definitio 이 그렇습니다. 아직은 그냥 패스...). int 대신 long, short 를 선언해 주어도 됩니다. 이제 더 나가서 값을 넣어 볼까요.
------------------------------------------------------------------------
/* 예제 04.02 */
#include <stdio.h>
#include <stdlib.h>
int main()
{
int var; /* 1) */
var = 1; /* 2)값 대입 */
printf("%d \n", var); /* 3) */
system("PAUSE");
return 0;
}
------------------------------------------------------------------------
1이 라는 값이 출력됩니다. 당연한 말이지만, 1이라는 값은 var 가 가지고 있던 값입니다.
주석 2) 에서 var 는 이제 1 이라는 값을 가지게 됩니다. 이것은 수학에서 미지수 var 에 1 이라는 값을 대입하는 것과 같다고 보시면 됩니다.
주석 3)에서는 var 가 가지고 있는 값을 출력하라고 요구합니다.
주석 3) 다시 써 보면
printf("%d \n", 1); /* 3) */
이라고 쓴 것과 같습니다. %d 는 문자형 변수 또는 상수를 출력할 때 사용하는 형식입니다.
주석 1) 과 주석 2)를 동시에 할 수도 있습니다.
int var = 1;
처럼 할 수도 있습니다. 이런면 정의와 초기화를 함께 할 수 있습니다.
주석 2) 에서 1 이라는 값 대신 다른 값을 넣고 다시 컴파일 해서 실행해 보세요. 그러면 그 넣은 값이 출력 될 것입니다. 여기서는 1 대신 정수만 집어넣을 수 있습니다.
int 대신에 사용될 수 있는 자료형은 long 과 short 이 있습니다.
long var; 이라고 long 을 사용하면 주석 2) printf("%d \n", var); 대신에 printf("%ld \n",var) 라고 해주어야 합니다.
( % 다음에 붙는 많은 문자들이 생각을 혼란스럽게 할 지도 모릅니다. 그리고 그게 무엇하는지도 모르겠죠. 지금은 잠시 print 에 대한 생각을 접어두고 변수가 무엇인가 그리고 자료형이라는 게 무엇인가 하는데 생각을 집중해 주세요.)
보통 32비트 컴퓨터 시스템과 32비트를 지원하는 컴파일러에서는 short 2byte, int 4byte, long 은 4byte의 메모리 공간을 차지합니다. (물론 내가 앞에서부터 설명한 Visual C, Dev-cpp 는 이 조건에 따릅니다.) 그리고 int 는 CPU가 처리할 수 있는 알맞은 크기입니다. 그래서 보통 int 를 많이 사용합니다.
메모리 크기의 영향으로 저장할 수 있는 한계가 있습니다. Visual C 6.0 와 Dev-cpp 을 기준으로 short 은 -32768 ( - 2^15) 에서 32767 (2^15 - 1 ) 까지의 숫자만 표현할 수 있습니다.
int 와 long 은 -2147483648 (-2 ^ 31) 에서 2147483647 (2^31 - 1) 까지의 수만 표현 할 수 있습니다. ( 여기서 사용된 2 ^ 15 같은 기호는 2의 15승 이라는 거듭제곱 연산을 말합니다. 이는 C 형식의 표현방법이 아닙니다. 보통 컴퓨터 상에서 거듭제곱을 ^ 를 이용해서 표시합니다. )
한 번 그 이상의 값을 넣어보십시오.
------------------------------------------------------------------------
/* 예제 04.02 의 변형 1 */
#include <stdio.h>
#include <stdlib.h>
int main()
{
short var; /* 1) */
var =32768 ; /* 2)값 대입 */
printf("%d \n", var); /* 3) */
system("PAUSE");
return 0;
}
------------------------------------------------------------------------
이런 식으로 값을 넣는다면 의도한 대로 값을 출력하지 않습니다.
04.05 부동소수형
앞서 배운 예제에서 주석2)만 조금 고치면 조금만 고쳐보겠습니다.
------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
int main()
{
int var; /* 1) */
var = 1.1; /* 2)값 대입 */
printf("%d \n", var); /* 3) */
system("PAUSE");
return 0;
}
------------------------------------------------------------------------
이 때 var 에는 1.1 이라는 소수를 저장할 수 없습니다. 이 코드는 1 이라고 1단위 이하 소수단위가 잘려서 나옵니다. 1단위에서 버림 한다고 할까요. C 에서 소수(일본 컴퓨터 용어를 이용하자면 "부동 소수점(浮動小數點 )"[floating point] 라고 합니다. )를 다루기 위해서는 float, double, long double 을 사용합니다. 보통 float 는 4바이트, double 은 8바이트입니다. (long double 은 visual c 에서 8바이트로 double 과 같습니다. 내부적으로 long double 을 double 로 바꾼다고 합니다. dev-cpp 는 long double 이 12 바이트입니다. 이건 저 조차 이해가 안가는 일이라서 조금 더 봐야 될 것 같군요. 이게 x86 시스템에서 가능한지 좀 의문이라서. )
float, double, long double을 묶어서 실수형이라고 부릅니다.
float 과 double 도 메모리의 영향으로 표현할 수 있는 수에 한계가 있습니다. float 은 십진수를 기준으로 유효숫자가 6자리에 1.17549435e-38 에서 3.40282347e+38F 수 사이의 수를 표시할 수 있습니다.( 여기서 e 라는 기호는 씨언어에서도 사용되는 기호로 지수를 나타낼 때 사용됩니다. 계산기에서 사용되는 형식과 동일합니다. ) ( 여기에 사용된 유효숫자와 범위는 float.h 에 정의된 define 문을 참조했습니다). 물론 - 부호에 대한 사용도 가능합니다. double 은 10진수를 기준으로 15자리 유효숫자와 2.2250738585072014e-308 에서 1.7976931348623157e+308 사이의 값을 표현할 수 있습니다.( 더 자세히 알고 싶은 분은 IEEE754 규정을 찾아보세요. 나중에 마이크로프로세스라는 과목을 듣게 된다면 여기에 대해 배우게 됩니다.)
앞의 예제가 제대로 작동하기 위해서는 2군데를 고쳐야 합니다. 주석 1과 3을 다음과 같이 고쳐야 잘 작동합니다.
------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
int main()
{
double var; /* 1) */
var = 1.1; /* 2)값 대입 */
printf("%f \n", var); /* 3) */
system("PAUSE");
return 0;
}
------------------------------------------------------------------------
이렇게 고치면 우리가 원하는 값 1.1을 출력해서 보여줍니다. 주석 1에서 double 대신 float을 사용할 수 있습니다.
04.06 문자형
---------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
int main()
{
char var; /* 1) */
var = 'A'; /* 2)값 대입 */
printf("%c \n", var); /* 3) */
system("PAUSE");
return 0;
}
------------------------------------------------------------------------
이 예제는 A 라는 값을 출력합니다. 컴퓨터 안에서는 모든 데이터는 0과 1로만 표현합니다. 그래서 문자도 결국 숫자로 표현됩니다. C 에서는 기본적으로 아스키코드를 이용해 문자를 표현합니다. 'A' 는 65 라는 아스키 값을 대표합니다.
주석 (3) 을
printf("%d \n", 'A' ); /* 3) */
라고 고쳐보세요. 그러면 65 라는 값을 출력합니다. 앞에서 %d 는 정수를 출력한다고 말했습니다. 이번에는
printf("%c \n", 'A' ); /* 3) */
라 고쳐보세요. 바로 앞의 예제와 같이 영문자 A 를 출력합니다.
이번에는
printf("%c \n", 65 ); /* 3) */
라고 고쳐보십시오. 똑 같이 'A'라는 값을 출력합니다. 이 부분은 상수를 설명하는 곳에서 더 자세히 설명하겠습니다.
char 형은 일반적으로 1 byte이기 때문에 이 자체만으로 우리 한글을 표현할 수 없습니다. 아스키 코드표를 찾아보면 알겠지만 알파벳 대소문자, 숫자, 기호 정도 입니다. 나중에 배울 char 의 배열을 이용해서 표현하게 됩니다.
( 참고적으로 C 에서는 확장형(wide character) 문자타입이라는 것을 지원합니다. wchar_t 라는 형입니다. 이 부분은 오래된 컴파일러에서는 지원하지 않을 수 있습니다.
이 확장형은 시스템마다 차이가 매우 크다고 합니다. 어떤 곳에서는 2바이트로 정의 되어 있고, 어떤 곳에서는 4바이트로 정의 되어 있다고 합니다. Visual Stdio 6.0에서는 2byte이고 GCC계열에서는 4byte로 나옵니다. 유니코드라는 것도 이 확장형 문자를 통해 표현 할 수 있습니다. 그런데 이 확장형을 많이 안 사용합니다. 저도 많이 안 사용해 어떤 게 이것을 출력하는지도 모르겠습니다. 그래서 저도 설명을 포기했습니다. 죄송합니다. 말했다시피 저도 초보입니다.
)
char 형이 조금 독특한게 char 형으로도 정수형을 저장할 수 있습니다. 1byte이기 때문에 일반적으로 -127 ~ 128 까지의 숫자를 저장할 수 있습니다.
주석 2를 고쳐 다음과 같이 숫자를 직접 대입할 수도 있습니다.
---------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
int main()
{
char var; /* 1) */
var = 65; /* 2)값 대입 */
printf("%c \n", var); /* 3) */
system("PAUSE");
return 0;
}
------------------------------------------------------------------------
변수를 사용할 때, 주의사항이 있습니다. 조금 오래전에 만들어진 컴파일러에서는(Visaul Stdio 6.0 을 포함함) 변수 그리고 다음에 나오는 상수를 선언할 때는 꼭 블럭(중괄호로 둘러싸인 부분)이나 프로그램의 첫 부분에 나와야 합니다. C99 를 지원하는 컴파일러에서는 이것에 대한 제한이 없으나 조금 오래된 컴파일러는 이것을 에러로 인식합니다. 그래서 다음과 같은 경우 컴파일이 안 될 수 있습니다.
-------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("Hello, world\n");
int var;
var = 1;
printf("%d\n", var);
system("PAUSE");
return 0;
}
------------------------------------------------------------------------
나중의 for 문을 배우다 보면 이게 조금 답답해 보일 수도 있습니다.
끝으로 정리하겠습니다. 기본 자료형에는 정수형, 실수형(또는 "부동소수형"이라고 부르기도 합니다.), 문자형이 있습니다. 이 중 정수형에는 short, int , long 이 있고 이 중 int 형을 가장 많이 사용합니다. 실수형에는 float, double, long double 이 있고 이 중 double 형을 일반적으로 가장 많이 사용합니다. ( float 도 많이 이용하지만 long double 은 특수한 경우를 빼고는 거의 이용하지 않습니다.) 문자형으로는 char 형이 있고 이는 아스키 문자 하나를 담을 수 있습니다. char 형은 정수형 숫자를 담을 수 있기 때문에 정수형으로도 이용할 수 있습니다.
다음은 상수를 배우기로 하겠습니다.
참고사항
#1 32 비트 컴퓨터란??
요즘에 64비트 CPU가 일반 PC 용으로 나왔다는 말을 들어보신 적 있나요? 컴퓨터에 붙는 16비트, 32비트 이런 컴퓨터가 무엇을 뜻하는지 알고싶지 않습니까?
사실 이런 분류를 나누는 게 꽤나 어렵습니다. 정확한 정의가 없을 뿐더러 제품을 판매하는 회사에서 악용할 여지도 많습니다.
일반적인 정의를 말하면 CPU안에 ALU 라는 정치가 있습니다. 이 장치 연산을 하는 장치입니다. ALU에서 한 번에 계산할 수 있는 비트로 16비트,32비트 등으로 나눕니다. (한 번이라는 말도 약간의 왜곡이 생길 수 있을 것 같군요. 한 번이라는 말이 꼭 한 clock 을 의미하는 말은 아닙니다.)
다른 정의에서는 CPU 와 메모리 사이에 왔다갔다할 수 있는 비트의 수를 말합니다. 또, 다른 정의도 많았는데 기억이 안 나고요.
정확한 32비트 컴퓨터가 되려면 이 모든 것이 32비트면 되겠죠..
그리고 컴퓨터만 32비트라고 해서 32비트 모두를 사용할 수는 없습니다. 운영체제가 따라와주어야 하고, 그 운영체제 안의 프로그램도 32비트를 지원해야합니다. 더블어 우리 입장에서는 컴파일러도 32비트를 지원해야 32비트 프로그래밍을 할 수 있습니다.
#2 C언어에서 선언(Declarations)과 정의(Definitions)
다음은 C 프로그래밍을 만든 Dennis M.Ritchie 의 책"The C Programming Language" 186페이지 정리한 내용입니다.
선언 : 기억장소를 할당하지 않는다.
정의 : 기억장소를 할당하는 선언
조금 덧 붙이자면 나중에 배울 include를 이용할 때 이러한 변수가 다른 헤더파일에 있다는 것을 알리는게 정의이고 그냥 일반적으로 이런 변수를 앞으로 사용하겠다고 요구하는게 선언입니다. (물론 같은 헤더파일안에서도 정의를 사용해야 하는 경우가 있습니다. 서로 순환적인 구조를 같는 구조체의 경의가 이 경우입니다.)
이 강의에서는 이런 부분까지 세세히 구별하지 않았습니다.
초보자의 경우 이런부분까지 설명하면 머리아플 것이니 그냥 넘어가는 게 좋을 것 같군요.(솔직히 저도 얼마전에 안 사실입니다. )
덧 글(덧붙이는 글)
자료형에 정수형과 문자에 대해 unsigned 형이라는 게 있습니다. unsigned int . unsigned long, unsigned short, unsigned char 같은 식으로 쓰입니다. 이 형은 0과 양수에 대해 저장하도록 하여 넣을 수 있는 값을 범위를 2배로 늘렸습니다. 그런데 이런 거 까지 설명하면 처음 배우는 사람에게 너무 부담을 주는 것 같아서 뺏습니다.
또 여기서는 일반적인 32비트 컴파일러를 기준으로 자료형의 크기를 설명했습니다. C에서 정의하고 있는 자료형의 크기는 short <= int <= long 으로 되어 있습니다. 그래서 일반적인 16비트 시스템에서는 short, int 를 2바이트로, long을 4바이트 되어 있습니다.
작성자 : 한밀(승룡)
버전 : 0.1.5
이 글은 계속 고쳐지고 있습니다.
2003년 12월 어느 추운 날
최종 수정일 : 2007년 7월 중순, 날씨가 더워 잠을 못 자고 있는 어느 날
***** ljh131님에 의해서 게시물 복사 + 카테고리변경되었습니다 (2007-08-03 14:17)
===================================================
#04.초보가 쓰는 C 언어 강좌
(메모리와 변수)
04.01 메모리에 대해
컴퓨터는 크게 기억장치부분, 연산부분, 입출력부분으로 나눌 수 있습니다. 기억장치는 우선 메모리를 말하며 보조기억 장치로는 하드디스크 CD-ROM 같은 게 있고, 연산장치는 CPU를 말하며 (특히 ALU를 말합니다.) , 입출력부분은 키보드, 모니터처럼 우리가 컴퓨터를 조정하거나 그 결과를 보여주는 부분을 말합니다.
기억장치 중 메모리는 실행코드(프로그램언어를 컴파일 해둔 기계어)를 잠시 그 위에 옮겨둘 수 있고, 실행 결과를 저장할 공간을 제공합니다. 프로그램은 평상시에는 하드디스크 상에 있습니다. 사용자가 그 프로그램을 실행하면 운영체제가 알아서 메모리로 옮겨 주고, 결과를 저장할 공간을 실행프로그램을 봐가면서 메모리에 맞게 마련해 줍니다. 따라서 프로그래머는 이 프로그램은 이 공간이 필요하다고 말하기만 하면 됩니다. 그 때 사용하는 게 자료형이라는 것입니다.
04. 02 기본 자료형(Builtin Data Type)
C언어에서 메모리를 얻기 위해서는 자료에 맞는 메모리를 요구해야 합니다. 자료형(Data Type)은 크게 정수형(Integer), 부동소수형(Floating point), 문자형(Character)으로 나눌 수 있습니다. 정수형은 말 그대로 정수를 다루고, 부동소수형은 실수를 문자형은 문자를 다룹니다. 그리고 그 형은 내부적으로 크기에 따라 또 다시 나누어집니다.
왜, 이렇게 자료형을 나눌까요. 첫째는 메모리를 효율적으로 사용하기 위해서 입니다. 당연히 효율적으로 사용해야 메모리를 적게 사용할 수 있겠죠. 또, 자료에 맞는 연산(계산)을 하기 위해서 입니다. 소수점 계산하는 곳과 정수를 계산하는 곳은 CPU 내에 따로 위치해 있습니다.
04.03 변수(Variable)
수학에서 많이 들었던 낱말입니다. 쉽게 말해 변하는 수입니다. 보통 수학에서 함수를 사용할 때 쓰는 x 같은 문자와 비슷한 개념입니다. 변수는 자료형과 같이 쓰입니다. int a; 처럼. 여기서 a 가 변수입니다. 우리는 a, 대신 다른 이름을 줄 수 있습니다. 바로 앞 강좌에 심볼 이름 붙이는 규칙이 있습니다. 그 규칙에 맞는 여러 이름을 줄 수 있습니다. int a; 처럼 이렇게 변수를 만드는 행위를 변수를 선언한다(declaration) 고 합니다. (정확히 더 따지고 들어가면 선언:declaration와 정의:definition을 명확히 구별해서 사용해야 하겠으나 그러면 처음 배우는 사람들에게는 머리 복잡하니 구별하지 않겠습니다.)
변수가 변하는 수라는 말에 걸맞게 값을 여러가지 넣어 줄 수 있습니다. 당연히 사용하기 전, 맨 마지막에 넣어준 값만 기억하고 있습니다. 그리고 맨 처음 넣어주는 행위를 특별히 초기화 한다고 합니다.
04.04 정수형
정수형에는 int, short, long 이 있습니다. 바로 앞 강좌에 키워드라는 주제를 가진 글에 이 세 가지가 다 있습니다. 여기서 가장 중요한 것은 int 입니다.
Project 를 만들어 다음 예제를 실행해 보세요 (Project 만들 줄 모르신다면 앞의 강좌를 다시 읽어보세요.)
-----------------------------------------------------------------------------
/* 예제 04.01 */
#include <stdio.h>
#include <stdlib.h>
int main()
{
int var; /*1) var 라는 정수형 변수 선언 */
system("PAUSE");
/* Visual C를 사용한다면 이 부분은 없어도 됩니다. */
return 0;
}
-------------------------------------------------------------------------
컴파일 해서 실행하면 아직은 아무것도 안 나옵니다. 여기서 주석 1) 에서 int 형 변수 var 를 정의했습니다. 선언은 공간을 만들어 달라고 컴파일러에게 요구하는 것입니다(정확히는 definitio 이 그렇습니다. 아직은 그냥 패스...). int 대신 long, short 를 선언해 주어도 됩니다. 이제 더 나가서 값을 넣어 볼까요.
------------------------------------------------------------------------
/* 예제 04.02 */
#include <stdio.h>
#include <stdlib.h>
int main()
{
int var; /* 1) */
var = 1; /* 2)값 대입 */
printf("%d \n", var); /* 3) */
system("PAUSE");
return 0;
}
------------------------------------------------------------------------
1이 라는 값이 출력됩니다. 당연한 말이지만, 1이라는 값은 var 가 가지고 있던 값입니다.
주석 2) 에서 var 는 이제 1 이라는 값을 가지게 됩니다. 이것은 수학에서 미지수 var 에 1 이라는 값을 대입하는 것과 같다고 보시면 됩니다.
주석 3)에서는 var 가 가지고 있는 값을 출력하라고 요구합니다.
주석 3) 다시 써 보면
printf("%d \n", 1); /* 3) */
이라고 쓴 것과 같습니다. %d 는 문자형 변수 또는 상수를 출력할 때 사용하는 형식입니다.
주석 1) 과 주석 2)를 동시에 할 수도 있습니다.
int var = 1;
처럼 할 수도 있습니다. 이런면 정의와 초기화를 함께 할 수 있습니다.
주석 2) 에서 1 이라는 값 대신 다른 값을 넣고 다시 컴파일 해서 실행해 보세요. 그러면 그 넣은 값이 출력 될 것입니다. 여기서는 1 대신 정수만 집어넣을 수 있습니다.
int 대신에 사용될 수 있는 자료형은 long 과 short 이 있습니다.
long var; 이라고 long 을 사용하면 주석 2) printf("%d \n", var); 대신에 printf("%ld \n",var) 라고 해주어야 합니다.
( % 다음에 붙는 많은 문자들이 생각을 혼란스럽게 할 지도 모릅니다. 그리고 그게 무엇하는지도 모르겠죠. 지금은 잠시 print 에 대한 생각을 접어두고 변수가 무엇인가 그리고 자료형이라는 게 무엇인가 하는데 생각을 집중해 주세요.)
보통 32비트 컴퓨터 시스템과 32비트를 지원하는 컴파일러에서는 short 2byte, int 4byte, long 은 4byte의 메모리 공간을 차지합니다. (물론 내가 앞에서부터 설명한 Visual C, Dev-cpp 는 이 조건에 따릅니다.) 그리고 int 는 CPU가 처리할 수 있는 알맞은 크기입니다. 그래서 보통 int 를 많이 사용합니다.
메모리 크기의 영향으로 저장할 수 있는 한계가 있습니다. Visual C 6.0 와 Dev-cpp 을 기준으로 short 은 -32768 ( - 2^15) 에서 32767 (2^15 - 1 ) 까지의 숫자만 표현할 수 있습니다.
int 와 long 은 -2147483648 (-2 ^ 31) 에서 2147483647 (2^31 - 1) 까지의 수만 표현 할 수 있습니다. ( 여기서 사용된 2 ^ 15 같은 기호는 2의 15승 이라는 거듭제곱 연산을 말합니다. 이는 C 형식의 표현방법이 아닙니다. 보통 컴퓨터 상에서 거듭제곱을 ^ 를 이용해서 표시합니다. )
한 번 그 이상의 값을 넣어보십시오.
------------------------------------------------------------------------
/* 예제 04.02 의 변형 1 */
#include <stdio.h>
#include <stdlib.h>
int main()
{
short var; /* 1) */
var =32768 ; /* 2)값 대입 */
printf("%d \n", var); /* 3) */
system("PAUSE");
return 0;
}
------------------------------------------------------------------------
이런 식으로 값을 넣는다면 의도한 대로 값을 출력하지 않습니다.
04.05 부동소수형
앞서 배운 예제에서 주석2)만 조금 고치면 조금만 고쳐보겠습니다.
------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
int main()
{
int var; /* 1) */
var = 1.1; /* 2)값 대입 */
printf("%d \n", var); /* 3) */
system("PAUSE");
return 0;
}
------------------------------------------------------------------------
이 때 var 에는 1.1 이라는 소수를 저장할 수 없습니다. 이 코드는 1 이라고 1단위 이하 소수단위가 잘려서 나옵니다. 1단위에서 버림 한다고 할까요. C 에서 소수(일본 컴퓨터 용어를 이용하자면 "부동 소수점(浮動小數點 )"[floating point] 라고 합니다. )를 다루기 위해서는 float, double, long double 을 사용합니다. 보통 float 는 4바이트, double 은 8바이트입니다. (long double 은 visual c 에서 8바이트로 double 과 같습니다. 내부적으로 long double 을 double 로 바꾼다고 합니다. dev-cpp 는 long double 이 12 바이트입니다. 이건 저 조차 이해가 안가는 일이라서 조금 더 봐야 될 것 같군요. 이게 x86 시스템에서 가능한지 좀 의문이라서. )
float, double, long double을 묶어서 실수형이라고 부릅니다.
float 과 double 도 메모리의 영향으로 표현할 수 있는 수에 한계가 있습니다. float 은 십진수를 기준으로 유효숫자가 6자리에 1.17549435e-38 에서 3.40282347e+38F 수 사이의 수를 표시할 수 있습니다.( 여기서 e 라는 기호는 씨언어에서도 사용되는 기호로 지수를 나타낼 때 사용됩니다. 계산기에서 사용되는 형식과 동일합니다. ) ( 여기에 사용된 유효숫자와 범위는 float.h 에 정의된 define 문을 참조했습니다). 물론 - 부호에 대한 사용도 가능합니다. double 은 10진수를 기준으로 15자리 유효숫자와 2.2250738585072014e-308 에서 1.7976931348623157e+308 사이의 값을 표현할 수 있습니다.( 더 자세히 알고 싶은 분은 IEEE754 규정을 찾아보세요. 나중에 마이크로프로세스라는 과목을 듣게 된다면 여기에 대해 배우게 됩니다.)
앞의 예제가 제대로 작동하기 위해서는 2군데를 고쳐야 합니다. 주석 1과 3을 다음과 같이 고쳐야 잘 작동합니다.
------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
int main()
{
double var; /* 1) */
var = 1.1; /* 2)값 대입 */
printf("%f \n", var); /* 3) */
system("PAUSE");
return 0;
}
------------------------------------------------------------------------
이렇게 고치면 우리가 원하는 값 1.1을 출력해서 보여줍니다. 주석 1에서 double 대신 float을 사용할 수 있습니다.
04.06 문자형
---------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
int main()
{
char var; /* 1) */
var = 'A'; /* 2)값 대입 */
printf("%c \n", var); /* 3) */
system("PAUSE");
return 0;
}
------------------------------------------------------------------------
이 예제는 A 라는 값을 출력합니다. 컴퓨터 안에서는 모든 데이터는 0과 1로만 표현합니다. 그래서 문자도 결국 숫자로 표현됩니다. C 에서는 기본적으로 아스키코드를 이용해 문자를 표현합니다. 'A' 는 65 라는 아스키 값을 대표합니다.
주석 (3) 을
printf("%d \n", 'A' ); /* 3) */
라고 고쳐보세요. 그러면 65 라는 값을 출력합니다. 앞에서 %d 는 정수를 출력한다고 말했습니다. 이번에는
printf("%c \n", 'A' ); /* 3) */
라 고쳐보세요. 바로 앞의 예제와 같이 영문자 A 를 출력합니다.
이번에는
printf("%c \n", 65 ); /* 3) */
라고 고쳐보십시오. 똑 같이 'A'라는 값을 출력합니다. 이 부분은 상수를 설명하는 곳에서 더 자세히 설명하겠습니다.
char 형은 일반적으로 1 byte이기 때문에 이 자체만으로 우리 한글을 표현할 수 없습니다. 아스키 코드표를 찾아보면 알겠지만 알파벳 대소문자, 숫자, 기호 정도 입니다. 나중에 배울 char 의 배열을 이용해서 표현하게 됩니다.
( 참고적으로 C 에서는 확장형(wide character) 문자타입이라는 것을 지원합니다. wchar_t 라는 형입니다. 이 부분은 오래된 컴파일러에서는 지원하지 않을 수 있습니다.
이 확장형은 시스템마다 차이가 매우 크다고 합니다. 어떤 곳에서는 2바이트로 정의 되어 있고, 어떤 곳에서는 4바이트로 정의 되어 있다고 합니다. Visual Stdio 6.0에서는 2byte이고 GCC계열에서는 4byte로 나옵니다. 유니코드라는 것도 이 확장형 문자를 통해 표현 할 수 있습니다. 그런데 이 확장형을 많이 안 사용합니다. 저도 많이 안 사용해 어떤 게 이것을 출력하는지도 모르겠습니다. 그래서 저도 설명을 포기했습니다. 죄송합니다. 말했다시피 저도 초보입니다.
)
char 형이 조금 독특한게 char 형으로도 정수형을 저장할 수 있습니다. 1byte이기 때문에 일반적으로 -127 ~ 128 까지의 숫자를 저장할 수 있습니다.
주석 2를 고쳐 다음과 같이 숫자를 직접 대입할 수도 있습니다.
---------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
int main()
{
char var; /* 1) */
var = 65; /* 2)값 대입 */
printf("%c \n", var); /* 3) */
system("PAUSE");
return 0;
}
------------------------------------------------------------------------
변수를 사용할 때, 주의사항이 있습니다. 조금 오래전에 만들어진 컴파일러에서는(Visaul Stdio 6.0 을 포함함) 변수 그리고 다음에 나오는 상수를 선언할 때는 꼭 블럭(중괄호로 둘러싸인 부분)이나 프로그램의 첫 부분에 나와야 합니다. C99 를 지원하는 컴파일러에서는 이것에 대한 제한이 없으나 조금 오래된 컴파일러는 이것을 에러로 인식합니다. 그래서 다음과 같은 경우 컴파일이 안 될 수 있습니다.
-------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("Hello, world\n");
int var;
var = 1;
printf("%d\n", var);
system("PAUSE");
return 0;
}
------------------------------------------------------------------------
나중의 for 문을 배우다 보면 이게 조금 답답해 보일 수도 있습니다.
끝으로 정리하겠습니다. 기본 자료형에는 정수형, 실수형(또는 "부동소수형"이라고 부르기도 합니다.), 문자형이 있습니다. 이 중 정수형에는 short, int , long 이 있고 이 중 int 형을 가장 많이 사용합니다. 실수형에는 float, double, long double 이 있고 이 중 double 형을 일반적으로 가장 많이 사용합니다. ( float 도 많이 이용하지만 long double 은 특수한 경우를 빼고는 거의 이용하지 않습니다.) 문자형으로는 char 형이 있고 이는 아스키 문자 하나를 담을 수 있습니다. char 형은 정수형 숫자를 담을 수 있기 때문에 정수형으로도 이용할 수 있습니다.
다음은 상수를 배우기로 하겠습니다.
참고사항
#1 32 비트 컴퓨터란??
요즘에 64비트 CPU가 일반 PC 용으로 나왔다는 말을 들어보신 적 있나요? 컴퓨터에 붙는 16비트, 32비트 이런 컴퓨터가 무엇을 뜻하는지 알고싶지 않습니까?
사실 이런 분류를 나누는 게 꽤나 어렵습니다. 정확한 정의가 없을 뿐더러 제품을 판매하는 회사에서 악용할 여지도 많습니다.
일반적인 정의를 말하면 CPU안에 ALU 라는 정치가 있습니다. 이 장치 연산을 하는 장치입니다. ALU에서 한 번에 계산할 수 있는 비트로 16비트,32비트 등으로 나눕니다. (한 번이라는 말도 약간의 왜곡이 생길 수 있을 것 같군요. 한 번이라는 말이 꼭 한 clock 을 의미하는 말은 아닙니다.)
다른 정의에서는 CPU 와 메모리 사이에 왔다갔다할 수 있는 비트의 수를 말합니다. 또, 다른 정의도 많았는데 기억이 안 나고요.
정확한 32비트 컴퓨터가 되려면 이 모든 것이 32비트면 되겠죠..
그리고 컴퓨터만 32비트라고 해서 32비트 모두를 사용할 수는 없습니다. 운영체제가 따라와주어야 하고, 그 운영체제 안의 프로그램도 32비트를 지원해야합니다. 더블어 우리 입장에서는 컴파일러도 32비트를 지원해야 32비트 프로그래밍을 할 수 있습니다.
#2 C언어에서 선언(Declarations)과 정의(Definitions)
다음은 C 프로그래밍을 만든 Dennis M.Ritchie 의 책"The C Programming Language" 186페이지 정리한 내용입니다.
선언 : 기억장소를 할당하지 않는다.
정의 : 기억장소를 할당하는 선언
조금 덧 붙이자면 나중에 배울 include를 이용할 때 이러한 변수가 다른 헤더파일에 있다는 것을 알리는게 정의이고 그냥 일반적으로 이런 변수를 앞으로 사용하겠다고 요구하는게 선언입니다. (물론 같은 헤더파일안에서도 정의를 사용해야 하는 경우가 있습니다. 서로 순환적인 구조를 같는 구조체의 경의가 이 경우입니다.)
이 강의에서는 이런 부분까지 세세히 구별하지 않았습니다.
초보자의 경우 이런부분까지 설명하면 머리아플 것이니 그냥 넘어가는 게 좋을 것 같군요.(솔직히 저도 얼마전에 안 사실입니다. )
덧 글(덧붙이는 글)
자료형에 정수형과 문자에 대해 unsigned 형이라는 게 있습니다. unsigned int . unsigned long, unsigned short, unsigned char 같은 식으로 쓰입니다. 이 형은 0과 양수에 대해 저장하도록 하여 넣을 수 있는 값을 범위를 2배로 늘렸습니다. 그런데 이런 거 까지 설명하면 처음 배우는 사람에게 너무 부담을 주는 것 같아서 뺏습니다.
또 여기서는 일반적인 32비트 컴파일러를 기준으로 자료형의 크기를 설명했습니다. C에서 정의하고 있는 자료형의 크기는 short <= int <= long 으로 되어 있습니다. 그래서 일반적인 16비트 시스템에서는 short, int 를 2바이트로, long을 4바이트 되어 있습니다.
작성자 : 한밀(승룡)
버전 : 0.1.5
이 글은 계속 고쳐지고 있습니다.
2003년 12월 어느 추운 날
최종 수정일 : 2007년 7월 중순, 날씨가 더워 잠을 못 자고 있는 어느 날
***** ljh131님에 의해서 게시물 복사 + 카테고리변경되었습니다 (2007-08-03 14:17)
2007.11.25 02:30:59 (*.234.76.64)
좋은 강좌 감사합니다.
여기에 개인적인 의견이나, 이상한 곳(?) 짚어도 되죠? ^^
변수가 '변하는 수'라고 하셨는데... 이 말은 미묘한 오해를 일으킬 수 있는 것 같습니다.
사실 거의 누구나 '변하는 수'라고 표현하지만요. 그런데 Variable의 어딜 봐도, 또 실제 변수의 동작을 봐도 변수는 '변하는 수'가 아니라고 생각합니다.
극단적으로 말해 어디선가 안 건드리면, 안 변합니다. (멋대로 변하면 그것도 곤란한 일이죠...)
따라서 변수는 상수의 반대되는 의미로, '변할 수 있는 수' 내지는 '바꿀 수 있는 수'라고 하는게 옳다고 생각합니다. (그러면 상수는 '변할 수 없는 수', '바꿀 수 없는 수 '가 되겠죠)
이렇게 적으면 변수나 상수나 둘 다 어떤 값을 가지고 있다는 것은 같지만 단순히 "바꿀 수 있느냐 없느냐"의 차이, 즉 C에서 다루는 상수성에 대해 좀 더 잘 맞는 설명이라고 생각합니다. (const 키워드가 '한정자(Qualifier)'라는 이름을 가지는 이유라고도 할 수 있을 것 같네요. 단순히 '바꿀 수 있는'것을 제한하는 것이니...)
그건 그렇고요.
실수형은 기본적으로 80비트라고 알고 있습니다.
그런데 이 10바이트란 크기는 호환성 면에서 꽤 곤란한 것이죠.
MS껀 그냥 long double을 double로 취급하고, Dev-Cpp는 DWORD 정렬해서 12바이트로 하는 것 같은데요, 이런 식으로 10바이트는 정렬할 때 많이 곤란하기도 하고 해서 잘 안 쓰는 것으로 압니다. (이런 형식을 지원하는 언어의 문서에는 대부분 호환성을 떨어뜨린다고 사용할 때 주의하라고 적혀있더군요.)
여튼 10바이트입니다. 그리고 x86에서도 충분히 가능합니다 ^^; 왜냐면 FPU는 FPU로 실수를 로드할 때 CPU 레지스터에서 바로 가져올 수 있는 방법이 없고, 무조건 메모리를 통해 읽도록 되어 있거든요...
괜히 쓸데없이 길어진 것 같군요...^^;
여기에 개인적인 의견이나, 이상한 곳(?) 짚어도 되죠? ^^
변수가 '변하는 수'라고 하셨는데... 이 말은 미묘한 오해를 일으킬 수 있는 것 같습니다.
사실 거의 누구나 '변하는 수'라고 표현하지만요. 그런데 Variable의 어딜 봐도, 또 실제 변수의 동작을 봐도 변수는 '변하는 수'가 아니라고 생각합니다.
극단적으로 말해 어디선가 안 건드리면, 안 변합니다. (멋대로 변하면 그것도 곤란한 일이죠...)
따라서 변수는 상수의 반대되는 의미로, '변할 수 있는 수' 내지는 '바꿀 수 있는 수'라고 하는게 옳다고 생각합니다. (그러면 상수는 '변할 수 없는 수', '바꿀 수 없는 수 '가 되겠죠)
이렇게 적으면 변수나 상수나 둘 다 어떤 값을 가지고 있다는 것은 같지만 단순히 "바꿀 수 있느냐 없느냐"의 차이, 즉 C에서 다루는 상수성에 대해 좀 더 잘 맞는 설명이라고 생각합니다. (const 키워드가 '한정자(Qualifier)'라는 이름을 가지는 이유라고도 할 수 있을 것 같네요. 단순히 '바꿀 수 있는'것을 제한하는 것이니...)
그건 그렇고요.
실수형은 기본적으로 80비트라고 알고 있습니다.
그런데 이 10바이트란 크기는 호환성 면에서 꽤 곤란한 것이죠.
MS껀 그냥 long double을 double로 취급하고, Dev-Cpp는 DWORD 정렬해서 12바이트로 하는 것 같은데요, 이런 식으로 10바이트는 정렬할 때 많이 곤란하기도 하고 해서 잘 안 쓰는 것으로 압니다. (이런 형식을 지원하는 언어의 문서에는 대부분 호환성을 떨어뜨린다고 사용할 때 주의하라고 적혀있더군요.)
여튼 10바이트입니다. 그리고 x86에서도 충분히 가능합니다 ^^; 왜냐면 FPU는 FPU로 실수를 로드할 때 CPU 레지스터에서 바로 가져올 수 있는 방법이 없고, 무조건 메모리를 통해 읽도록 되어 있거든요...
괜히 쓸데없이 길어진 것 같군요...^^;
2007.11.25 02:37:49 (*.234.76.64)
잠깐, 제가 Dev-Cpp를 써본 적이 오래되어서 확실히 하고 싶습니다.
제 기억에 Dev-Cpp는 컴파일러라기보단, 개발 환경을 제공하는 도구였던 것으로 기억하고 있습니다.
그리고 기본적으로 컴파일러를 gcc를 쓰도록 설정되어 있던 것 같은데, 맞나요?
그게 맞다면 위에서 "…Dev-Cpp에서는…"이나 "…gcc에서는…"라고 따로 구별한게 별 의미가 없을 뿐더러 혼란만 생길 것 같아서요... ^^;
제 기억에 Dev-Cpp는 컴파일러라기보단, 개발 환경을 제공하는 도구였던 것으로 기억하고 있습니다.
그리고 기본적으로 컴파일러를 gcc를 쓰도록 설정되어 있던 것 같은데, 맞나요?
그게 맞다면 위에서 "…Dev-Cpp에서는…"이나 "…gcc에서는…"라고 따로 구별한게 별 의미가 없을 뿐더러 혼란만 생길 것 같아서요... ^^;
2007.11.25 03:49:04 (*.51.133.106)
그런데 실수형이 기본적으로 80비트라는건무슨 말인가요?
정하기 나름 아닌가요? float, double 같은건 IEEE 표준으로 있는데 말이죠.
정하기 나름 아닌가요? float, double 같은건 IEEE 표준으로 있는데 말이죠.
2007.11.25 05:15:22 (*.234.76.64)
x86에선 레지스터가 32비트이듯이, x87에선 실수 레지스터가 80비트더군요.
사실 저는 long double에 대한 표준을 모르기 때문에, 그런 추측성 발언을 한 거였죠.
int가 기계에 따라 다르듯이 long double도 그런 맥락에서 해석할 수 있지 않을까... 싶었답니다.
즉 int가 일반적으로 레지스터 크기듯이 long double도 레지스터 크기로, float이나 double처럼 딱 크기가 정해지지 않은... 그런 타입이라고 생각했거든요...
흔히 '호환성 문제가 있는' 타입들은 int나 포인터같이 '크기가 정확히 정해지지 않은' 놈들이므로, 마찬가지로 '호환성 문제가 있는' long double도 크기가 정해지지 않은 거라고 나름대로 추리(?) 한 겁니다. -_-;;
(기계 관점에서 보는) 정수의 기본형은 int듯이 실수의 기본형은 'long double인 것 같으므로' 80비트인 것 같다... 뭐 이렇게 이해해주시면 좋겠습니다 ^^;
사실 저는 long double에 대한 표준을 모르기 때문에, 그런 추측성 발언을 한 거였죠.
int가 기계에 따라 다르듯이 long double도 그런 맥락에서 해석할 수 있지 않을까... 싶었답니다.
즉 int가 일반적으로 레지스터 크기듯이 long double도 레지스터 크기로, float이나 double처럼 딱 크기가 정해지지 않은... 그런 타입이라고 생각했거든요...
흔히 '호환성 문제가 있는' 타입들은 int나 포인터같이 '크기가 정확히 정해지지 않은' 놈들이므로, 마찬가지로 '호환성 문제가 있는' long double도 크기가 정해지지 않은 거라고 나름대로 추리(?) 한 겁니다. -_-;;
(기계 관점에서 보는) 정수의 기본형은 int듯이 실수의 기본형은 'long double인 것 같으므로' 80비트인 것 같다... 뭐 이렇게 이해해주시면 좋겠습니다 ^^;
2007.11.25 13:22:37 (*.238.173.174)
제가 Dev-Cpp 와 gcc를 구별했던 것은 두 개가 다르다고 생각했기 때문입니다. 이 글을 처음 적기 시작할 때까 04년 이었는데, 컴파일러에 대한 지식이 많이 없었을 때입니다.
지금 컴파일러를 학교에서 공부하고 있는데, code generation 부분만 플랫폼에 맞게 수정하면 된다는 것을 알기 때문에 구별할 필요가 없는 것 같다는 것을 깨닫았내요. 나중에 리눅스에서도 실험해 보면서 gcc 라고 통일 해야 할 것 같아요.
그리고 gcc에서 long double이 12byte라는데 의문을 가졌던게 인텔에서 부동소스점이 10byte까지면 연산을 제공한데, 어떻게 그럴 수 있냐는 것이었는데 지상현님 때문에 의문이 풀렸내요. word 정렬을 하다보면 12byte가 더 자연스러운 것 같군요.
또, 변수에 대해서 단지 "변하는 수"라고 했던 것은 제가 처음 C를 배울 때 변수를 그렇게 느꼈기 때문입니다. 정확히는 container 개념을 설명해야 할 것 같은데, 제 머리로는 초보자를 쉽게 설명할 자신이 없었기에 제가 처음 느꼈던 느낌대로 설명한 것입니다.
지금 컴파일러를 학교에서 공부하고 있는데, code generation 부분만 플랫폼에 맞게 수정하면 된다는 것을 알기 때문에 구별할 필요가 없는 것 같다는 것을 깨닫았내요. 나중에 리눅스에서도 실험해 보면서 gcc 라고 통일 해야 할 것 같아요.
그리고 gcc에서 long double이 12byte라는데 의문을 가졌던게 인텔에서 부동소스점이 10byte까지면 연산을 제공한데, 어떻게 그럴 수 있냐는 것이었는데 지상현님 때문에 의문이 풀렸내요. word 정렬을 하다보면 12byte가 더 자연스러운 것 같군요.
또, 변수에 대해서 단지 "변하는 수"라고 했던 것은 제가 처음 C를 배울 때 변수를 그렇게 느꼈기 때문입니다. 정확히는 container 개념을 설명해야 할 것 같은데, 제 머리로는 초보자를 쉽게 설명할 자신이 없었기에 제가 처음 느꼈던 느낌대로 설명한 것입니다.
