C 언어 | C 언어 입문 | 변수와 데이터 유형
변수 선언과 데이터 유형에 대해 설명한다. 계산 결과 등을 프로그램 내에서 재사용하기 위해 임시로 저장하려면 변수를 사용한다.
변수의 정의 및 초기화
“정보 처리"는 정보를 컴퓨터에 입력하고, 프로그램이 이를 분석하여 원하는 형태로 변환하여 출력하는 기본적인 과정을 말한다. 이를 실행하려면 프로그램은 정보를 받아 계산해야 한다. 그러기 위해서는 먼저 정보를 기록하는 방법이 필요하다. 그렇지 않으면 받은 정보와 계산 결과를 저장할 수 없다.
그래서 프로그램은 일시적으로 정보를 주기억 장치에 저장하여 연산 결과 등을 기록한다. 주기억 장치는 CPU와의 데이터 전송 속도를 엄격하게 생각해서 구성되어 있는 휘발성(전원을 끄면 저장하고 있던 정보를 잃게 저장 장치) 장치로써 비트당 비용이 상대적으로 비싸다.
사용자가 데이터 파일을 저장하고 있는 저장 장치는 하드 디스크나 플로피 디스크이지만, 이러한 저장 장치는 CPU로의 데이터 전송 속도가 매우 느려서 프로그램의 일시적인 데이터 저장에는 적합하지 않다. 그 대신 주기억 장치에 비해 비트당 비용이 저렴하고, 비휘발성(전원 공급이 끊어져도 데이터를 저장할 수 있는 저장 장치)이므로 장기 데이터 저장에 적합하다.
주기억 장치에 정보를 저장하기 위해, 기계어에서는 저장할 위치를 나타내는 주소를 지정한다. 그러나 그런 귀찮은 것은 전문 프로그래머도 하고 싶은 작업이 아니다. 계산이 복잡하고, 조금이라도 잘못된 주소를 지정하면 프로그램은 충돌하게 된다. 이 작업은 누가 봐도 효율적이라고 할 수 없다.
그래서 고급 프로그래밍 언어에서는 변수를 사용한다. 변수는 메모리의 특정 저장소의 대명사와 같은 것이다. 변수는 식별자로 구분하고, 컴파일러는 식별자 및 물리적 저장 공간을 연결하여 정보의 쓰기와 읽기를 정확하게 수행한다. 따라서 우리는 복잡한 메모리 주소 계산에서 해방되어, 기억 공간의 할당 및 계산을 컴파일러에 맡길 수 있다. 따라서 초보자도 간단히 메모리를 사용할 수 있다.
그러나 변수는 메모리의 저장 공간을 나타내는 식별자이며, 실제 저장 공간은 크기가 존재한다. 어떤 저장 영역은 4바이트를 확보하고 있을 수도 있고, 다른 영역은 1바이트일 수도 있다. 이렇게 할당 저장 공간의 크기를 설정하기 위해 변수를 선언해야 한다. 여기에는 다음과 같은 구문을 사용한다.
변수 선언
유형 변수1, 변수2, ...;
유형은 형식 지정자라는 것을 지정한다. 형식 지정자는 변수의 종류를 나타내는 것으로, 컴파일러는 형식에 따라 메모리를 할당하고 메모리의 주소를 계산한다.
유형의 다음의 토큰은 변수의 이름을 지정한다. 변수 이름에는 문자와 숫자를 사용할 수 있지만, 첫번째 문자는 숫자를 사용하지 못하고 반드시 영문자 또는 밑줄(_)로 시작해야 한다. 또한, int와 return 등 C 언어를 사용하는 키워드를 식별자로 할 수 없다. 식별자의 대문자와 소문자는 구별된다. 이 식별자 명명 규칙은 C 언어의 모든 식별자의 이름에 해당된다.
여러 변수를 동시에 선언 또는 정의하려면 콤마(,)로 구분한다. 프로그램은 여기에 지정된 변수의 이름으로 기억 영역에 액세스할 수 있다. 마지막으로, 선언은 세미콜론(;)으로 종료한다. 구문상, 선언은 문장에 포함되지 않는다.
형식 지정자는 표1과 같다.
표1 - 형식 지정자
형식 지정자 | 크기 |
---|---|
char | 1바이트 |
int | CPU의 표준 정수 크기 |
float | 짧은 정밀도 부동 소수점 숫자 |
double | float형 이상, long double형 이하의 배정 밀도 부동 소수점 형 |
char형은 크기가 정해져 있기 때문에 매우 알기 쉽다. 이것은 영숫자 1문자분의 기억 영역을 나타낸다. int형이라는 것은 보통의 정수를 저장하기 위한 저장 공간으로, 그 크기는 컴퓨터에 따라 다르다. 이 크기는, 예를 들어 32비트 CPU라면 32비트(4바이트)를 할당할 수 있다. 64비트 CPU의 컴퓨터라면 64비트, 아주 오래된 CPU를 사용하는 16비트 시스템이면 16 비트가 할당된다는 것이다.
float와 double은 소수점을 취급하는 경우에 사용하는 저장 영역이다. 오차를 최대한 줄이고 싶은 계산 등에 사용할 수 있다. 이도 int 마찬가지로 기종에 따라 달라진다. 형식 지정자가 할당되는 구체적인 크기는 컴파일러 문서를 참조한다. 다음 문장은 정수형 변수 iVariable1과 iVariable2을 정의하고 있다.
int iVariable1 , iVariable2;
그러나, 이 시점에서 변수에 어떤 값이 저장되어 있는지 정해져 있지 않다 (아무 의미도 없는 부정 값이 저장되어 있다). 변수에 값을 저장하려면 대입 연산자 등호(=)를 사용하여 변수에 데이터를 할당한다. 다만, 일반적인 수학 표기법과 달리, 좌변에 대입하는 변수를 지정하고 오른쪽에 식을 기술한다. 예를 들어 다음 문장은 변수 iVariable1에 10이라는 값을 할당한다.
iVariable1 = 10;
이것은 iVariable1가 나타내는 기억 영역에 10이라는 값을 저장하는 것을 의미한다. 또한 이와는 별도로 변수를 선언할 때 초기 값을 주는 방법도 있다. 변수의 초기화에는 이니셜라이저를 사용한다.
유형 변수1 = 초기식1, 변수2 = 초기식2 ...;
형식 지정자 및 변수 이름 지정까지는 방금 전의 선언과 동일한다. 초기화는 등호(=)를 사용하여 변수의 초기 값을 나타내는 식을 지정한다. 초기화되지 않은 변수는 어떤 값이 대입될 때까지 어떤 값을 포함하고 있는지 보장되지 않는다. 확실히 변수에 초기 값을 할당하려면 이렇게 초기 값을 주는 것이 좋다.
코드1
#include <stdio.h>
int main()
{
int iVariable1 = 10 , iVariable2;
iVariable2 = 100;
return 0;
}
코드1는 변수를 선언하면 메모리에 지정된 영역을 확보하고 그 영역에 지정된 값을 대입하고 종료한다. 변수의 값을 화면에 표시하는 방법은 아직 설명하지 않기 때문에, 여기서는 실시하지 않는다. 그래서 이 프로그램은 오류가 발생하지 않으면 성공이다.
이 프로그램에서는 먼저 변수의 선언을 하고 있다. int iVariable1 = 10
이라는 것은 iVariable1라는 변수를 10으로 초기화하고 있다. 그 후에 콤마를 사용하여 iVariable2을 정의하고 있는데, 이 변수는 초기화되지 않는다. 이어 iVariable2 = 100
는 대입식을 이용하여 변수 iVariable2에 100을 대입하고 있다.
덧붙여서 식에서의 항목을 피연산자라고 한다. iVariable2 = 100
의 경우 iVaeiable2과 100는 피연산자이고, 등호(=)를 대입 연산자라고 한다. 다만, 이니셜라이저와 식을 혼동하지 말자. 변수 이니셜라이저에 사용되는 등호(=)는 일반적으로 대입식과는 기본적으로 이질적인 것이다.
서식 지정
그럼 이제 변수를 선언하고 값을 할당하는 방법은 알았다. 하지만 이것으로 정말 제대로 값이 할당되어 있는지 여부 모른다. 그래서 printf() 함수를 사용하여 변수의 내용을 출력하고 싶다.
printf() 함수에서 문자열이 아닌 값을 출력하려면, 서식 제어 문자열이라는 것을 서식 지정을 해야 한다. 형식 지정은 반드시 백분율 기호(%)로 시작하여, 왼쪽에서 오른쪽으로 해석되어 간다. printf() 함수는 단순히 리터럴 문자열을 출력하는 함수가 아니라, 실제 고급 형식 변환 함수에서 변수를 문자열의 어디에 어떤 형태로 할당할지 여부를 지정 할 수 있다. 그것을 수행하는 것이 서식 제어이다.
printf() 함수는 두번째 인수 이후에 임의의 수 만큼 인수를 지정할 수 있으며, 첫번째 인수에는 서식 제어 문자열을 지정한다. 서식 제어 문자열에 % 기호를 이용한 서식을 사용할 수 있으며, printf() 함수는 첫번째 형식 지정을 발견하면 두번째 인수의 변수를 지정한 형태로 출력하고, 두번째 서식 지정를 발견하면, 세번째 인수의 변수를 지정한 형태로 출력하는 같은 구조로 되어 있다. 따라서 서식 제어 문자열에 있는 서식의 수 만큼, 두번째 인수 이후에 변수를 지정한다. 서식 지정보다 인수의 수가 많으면 여분의 인수는 무시되지만, 서식 지정보다 인수의 수가 적은 경우, 동작은 보증되지 않는다.
printf() 함수의 서식 제어는 사실은 매우 복잡한 구조로 되어 있기 때문에 이 자리에서 자세한 설명은하지 않는다. 지금은 변수의 내용을 표시하는 데 필요한 형식만 설명한다.
서식 | 인수 형 | 변환 결과 |
---|---|---|
%d 또는 %i | int | 10 진수 정수 |
%x | int | 부호 없는 16 진수. 9 이상은 “abcdef"를 사용 |
%X | int | 부호 없는 16 진수. 9 이상은 “ABCDEF"를 사용 |
%c | int | 문자 |
%s | char * | 문자열 |
%f | double | 부동 소수점 [-]dddd.dddd 형식 |
%e | double | 부동 소수점 [-]d.dddd e [+]ddd 형식 |
%E | double | 지수의 앞에 붙는 것이 e 대신 E 인 점을 제외하고 %e 서식과 동일 |
%g | double | % f 또는 % e 중 지정된 값과 정확하게 표현 가능한 짧은 형식. |
%G | double | 지수 앞에있는 것이 e 대신 E 인 점을 제외하고는 %g의 서식과 동일 |
%% | - | 변환하지 않고 두 %보기 |
우선, 이 자리에서는 이것만 이해하고 있으면 충분하다. int 변수를 표시하려면 서식 지정에 %d를 지정하고 그 후에 인수 목적 변수를 지정한다. 예를 들어 printf("%d", iValiable);
라고 하면, iValiable 변수의 값이 표시된다. 인수를 복수 지정하는 경우, 인수는 콤마(,)로 구분한다.
코드2
#include <stdio.h>
int main() {
int iValiable = 10;
printf("iValiable = %d\n" , iValiable);
return 0;
}
이 프로그램을 실행하면 iValiable = 10
라고 화면에 표시된다. 이 결과를 보면 서식 제어 문자열에 지정된 %d가 iValiable의 내용으로 변환되어 있는 것을 알 수 있다.
형식 지정자의 혼합
변수 선언자에는 “변수의 정의 및 초기화"에서 소개한 기본형 이외에도 세부적 변수의 크기와 특성을 지정하는 형식 지정자가 존재한다. 방금 전에 소개한 기본적인 형식 지정자 외에, long과 short라는 지정자도 존재하고 이들을 이용하여 일반 숫자와는 다른 길이의 변수를 만들 수 있다. 이러한 형식 지정자를 사용하여 자격을 선언에는 다음과 같은 것이 있다.
형지정 | 크기 |
---|---|
short int | 16 비트, int 이하. int는 생략 가능. |
long int | 32 비트 이상, int와 동일하거나 그 이상. int는 생략 가능. |
long double | double과 같거나 그 이상. |
short int
나 long int
는 short나 long과 같이 생략된 형태를 사용하는 것이 가능하며, 일반적으로 생략한다. 일반적으로 short는 16비트 long은 32비트인 경우가 많을 것이다. 부동 소수점 형의 크기도 정수처럼 처리계에 의존하기 때문에 long double은 double과 같은 크기 일 수도 있고, 다를 수도 있다. 예를 들어 Microsoft Visual C ++ 6.0에서 long double은 80비트 (부호에 1비트, 지수에 15비트, 가수 64비트)로 되어 있다.
또한 숫자형 변수는 음수를 나타낼 수 있다. 그러나 음수를 표현하는 경우는 최상위 비트를 부호용으로 사용하기 때문에 표현 가능한 최대 값이 반이 되어 버리는 단점도 있다. 음수를 표현하지 않는 경우, 최상위 비트도 숫자 표현을 위해 사용할 수 얻으면, 표현할 수있는 범위가 확대된다.
그래서 부호가 있는 변수를 선언하는 경우 signed를 부호가 없는 경우는 unsigned 형 지정자를 사용한다. 일반적으로 signed를 분명히 적을 필요는 없지만, 컴파일러는 옵션으로 변수의 기본값을 부호 없이도 가능하고, 그러한 경우에 대비하여 음수를 취급하는 것을 명시적으로 표현하기 위해 사용할 수 있다. 음수를 취급할 필요가 없는 변수는 unsigned를 지정하여 높은 수치를 취급할 수 있게 된다.
예를 들어, 부호가 있는 char 형 변수는 -127 ~ +127 까지의 범위를 처리할 수 있다. 1바이트는 순수하게 생각하면 255까지, 이진수 1111 1111까지 이용할 수 있지만, 부호가 있는 경우는 이 중 최상위 비트가 플래그로 사용되기 때문에 부호가 있는 char 형 변수에 255을 대입하면 최상위 비트가 1이므로 음수 판단되며 2의 보수 표현으로는 2진수 1111 1111의 2의 보수를 구한 값 0000 0001 즉 -1이다. 색상 등의 정보를 1바이트로 취급 경우, 음수를 사용할 필요가 없기 때문에 unsigned를 사용하여 부호를 작성하는 방식이 사용된다.
코드3
#include <stdio.h>
int main() {
signed char chVariable = 255;
unsigned char uchVariable = 255;
printf("chVariable = %d\nuchVaruabke = %d\n" , chVariable , uchVariable);
return 0;
}
코드3은 부호가 있는 char형, 부호가 없는 char 형 변수에 255을 대입하고 있다. 계산대로 부호 있는 변수는 -1을 부호 없는 변수는 255을 출력한다. 그럼 1바이트의 변수에 대해 1바이트로 표현할 수 없는 높은 수치를 즉, 255 이상의 값을 대입하면 어떻게 될까? C 언어에서는 변수의 크기 이상의 값을 대입하면, 부호 없는 경우는 상위 비트가 비트가 잘려서 할당된다. 부호 있는 경우는 구현에 의존한다.