변수를 사용하려면 먼저 선언해야 한다. 선언(Declaration)이란 컴파일러에게 앞으로 이런 이런 이름을 가진 어떤 타입의 변수를 사용하겠으니 준비해 달라고 부탁하는 것이다. 예를 들어 Num이라는 이름으로 정수형 변수를 선언하면 컴파일러는 이 변수를 위해 정수형 하나를 저장할 수 있는 메모리 4바이트를 할당한다. 앞으로 이 메모리에 들어있는 값은Num이라는 변수 이름으로 참조하면 된다. 변수를 선언하는 기본 형식은 다음과 같다.

타입 변수명[=초기값][,변수명, 변수명, ...];

기본 형식에서 [ ] 괄호안에 있는 것은 모두 생략 가능하다는 뜻이며 ... 표기는 임의 개수만큼 반복될 수 있다는 뜻이다. 반드시 필요한 것은 타입과 변수명, 그리고 제일 끝에 있는 세미콜론밖에 없다. 변수 선언문도 문장이므로 끝에 세미콜론은 반드시 있어야 한다. 정수형 변수 Num을 선언하고 싶다면 다음과 같이 선언문을 작성한다.

int Num;

잠시 후에 다시 배우겠지만 정수형 타입은 int키워드로 표현한다. 이렇게 선언만 하면 Num을 위해 메모리가 할당된다. 그러나 할당만 되며 값은 초기화되지 않는데 C는 속도를 위해 특별한 지정이 없으면 변수값을 초기화하지 않는다. 성능을 최우선으로 하는 C의 특징을 잘 보여주는 대목이다. 이렇게 되면 변수는 할당된 번지에 원래부터 들어 있던 의미없는 값을 가지게 되며 이 값을 쓰레기값(Garbage)이라고 한다. 만약 선언과 동시에 어떤 값으로 초기화하고 싶다면 변수명 다음에 = 구두점을 쓰고 원하는 초기값을 뒤에 쓰면 된다.

int Num=12;

Num 변수가 선언됨과 동시에 이 변수가 12라는 값을 가지도록 초기화된다. C는 성능을 최우선으로 하기 때문에 명시적인 지정이 없으면 별다른 동작을 하지 않는다. 초기값이 필요없으면 선언만 하고 필요할 때만 초기값을 지정한다. 여러 개의 변수를 같은 타입으로 한꺼번에 선언할 수도 있는데 콤마로 구분된 변수명을 계속 나열하면 된다. 이때도 = 구분자로 그 중 일부를 초기화할 수 있다.

int a,b=3,c,d;

4개의 정수형 변수가 선언되며 이 중 b는 3으로 초기화된다. 물론 다음처럼 각각의 변수 선언을 별도의 명령으로 따로 선언해도 상관없다. 효과는 동일하지만 줄 수가 길어진다.

int a;

int b=3;

int c;

int d;

다른 타입의 변수는 한꺼번에 같이 선언할 수 없으며 각각 따로 선언해야 한다. 다음은 정수형 변수 두 개와 실수형 변수 하나를 선언한 것이다.

int angle, radius;

double ratio;

변수는 필요한만큼 얼마든지 선언할 수 있다. 앞장에서 실습했던 삼각형 그리기 예제를 보면 두 개의 정수형 변수 i와 j를 선언하고 있다.

Posted by 테티스
,

변수는 메모리의 위치를 기억한다고 했다. 그러나 실제로 컴파일러가 변수를 참조할 때는 메모리 번지를 참조하는 것이 아니라 번지에 기억된 값을 참조한다. 예를 들어 Num=56이라는 대입문이 있다고 하자. 컴파일러는 이 명령을 다음 둘 중 어떤 것으로 해석할까?

Num이 가리키는 번지를 56으로 바꾸어라.

Num이 가리키는 번지에 들어있는 값을 56으로 바꾸어라.

상식적으로 생각해 봐도 후자가 맞다. 변수는 내부적으로 번지에 대한 위치를 가리키지만 컴파일러는 변수를 번지에 기억된 값으로 참조한다. 즉, 변수의 실체는 번지가 아니라 그 번지에 기록된 값이다. 컴파일러가 변수를 통해 값을 참조하기 위해서는 단순히 메모리 위치만 알아서는 안된다. Num이 1234번지를 가리키고 있다고 할 때 "Num을 읽어라"는 명령을 내리면 1234번지부터 어디까지를 읽어야 하는 것인지를 알아야 하므로Num의 길이가 필요하다.

또한 읽은 값을 어떻게 해석할 것인가도 알아야 한다. 메모리에는 0과 1만 나열되어 있으므로 위치와 길이 정보만으로는 값의 형태를 파악할 수 없다. 1234번지에 들어있는 값이 정수인지 실수인지 또는 구조체인지 등의 정보가 있어야 컴파일러가 이 값을 정확하게 해석할 수 있다. 정수와 실수는 값의 형태가 다르며 메모리에 기록되는 방식도 당연히 다르다. 그래서 변수로부터 값을 정확하게 읽으려면 변수의 형태에 대해서도 알아야 한다.

사용자 삽입 이미지
변수는 저장된 메모리 위치와 함께 길이와 형태에 대한 정보를 가지는데 이런 변수의 특성을 타입(Type)이라고 한다. 타입이란 컴파일러가 변수를 읽고 쓰는 방법에 대한 정보이며 타입에 따라 Num은 정수형 변수이고 Average는 실수형 변수임을 알 수 있게 된다. C언어는 아주 많은 타입을 지원한다. 일단 어떤 타입들이 있는지 정리해 보자. 크게 기본형과 유도형으로 나누어진다. 

구분

타입

설명

기본형

정수형

정수

문자형

문자

실수형

실수

열거형

가능한 값들에 대한 나열형

void

타입이 정해지지 않은 자료형

유도형

배열

같은 타입의 자료 집합

구조체

다른 타입의 자료 집합

공용체

메모리를 공유하는 자료 집합

포인터

대상체의 번지를 가리키는 타입

함수형

함수의 번지를 가리키는 타입


기본형이란 하나의 단일 값을 기억하는 단순한 타입이다. 정수값 하나를 기억하는 정수형이 가장 직관적으로 이해하기 쉽고 사용 빈도도 높다. 정수형 변수는 1234나 38같은 정수값 하나를 저장할 수 있고 실수형 변수는 3.14나 1.5 같은 실수값 하나를 저장할 수 있다. 기본형은 전부 수치를 저장한다는 점에서 공통적이다.

유도형은 기본형으로부터 만들어지는 타입이다. 같은 종류의 변수 여러 개를 모으면 배열이 되고 다른 종류의 변수 여러 개를 모으면 구조체가 된다. 유도형은 다소 복잡하기 때문에 이 장에서는 소개만 하고 관련 장에서 다시 상세하게 다룰 것이다. 각 타입별로 한 장 이상씩을 차지할 정도로 유도형은 복잡하다.

Posted by 테티스
,

C는 다양한 데이터 타입을 제공하는데 이 장에서는 데이터 타입에 대해 알아볼 것이다. 다소 이론적인 내용에 대해서 다루며 재미있는 실습이 많지 않기 때문에 지루한 감이 있겠지만 변수는 프로그래밍의 가장 기본적인 도구이므로 당장 다 암기하지는 못하더라도 개념에 대해서는 꼭 정리를 하고 넘어가야 한다.

변수는 프로그래밍에 입문하는 사람들이 가장 먼저 배워야 하는 개념이다. 말뜻 그대로 풀어 보자면 변할 수 있는 수, 즉 고정되어 있지 않은 수라는 뜻이며 1이나 45 또는 3.14같은 상수의 반대 개념이다. 이름은 변수이지만 반드시 수치값만 저장되는 것은 아니며 문자열이나 포인터같은 좀 더 복잡한 값도 저장될 수 있다. 변수에서 말하는 수(數)를 좀 더 일반적으로 표현하면 데이터(data)이며 한국말로 알아듣기 쉽게 설명하면 값이다.

컴퓨터의 주 기억 장치는 메모리(RAM)이며 컴퓨터가 하는 주된 일이란 메모리에 기록된 값을 처리해서 입출력하는 것이다. 메모리의 값을 화면으로 보내면 출력하는 것이고 프린터로 보내면 인쇄하는 것이고 키보드에 입력된 문자를 메모리로 읽어들이면 이것이 바로 입력이다. 컴퓨터가 하는 여러 가지 복잡한 동작들도 알고 보면 메모리에 있는 값을 연산, 조작하여 주변 장치로 보내는 아주 간단한 동작의 조합에 불과하다. 심지어 인터넷 검색이나 동영상 재생같은 복잡한 동작도 메모리와 주변장치(화면, 네트워크 카드) 사이의 입출력이다.

80386이상의 CPU는 최대 4G까지의 메모리를 장착할 수 있다. 40억개나 되는 이런 기억 소자들에 대해 이놈, 저놈, 개똥이, 말똥이 같은 이름을 일일이 붙여줄 수는 없다. 그래서 컴퓨터는 연산 대상 메모리의 위치를 구분하기 위해 숫자로 된 번지(Address)라는 개념을 사용한다. 메모리를 구성하는 각 바이트들은 0부터 시작해서 40억까지의 고유한 번지를 가지고 있으며 이 번지를 대상으로 값을 읽거나 쓴다. 예를 들어 "1234번지에서 1237번지까지의 4바이트에 56을 기록한다" 는 식으로 동작한다.

그런데 번지라는 것은 사람의 입장에서 보면 굉장히 다루기 힘든 형태로 되어 있다. 번지는 값이 크기 때문에 통상 8자리의 16진수로 표현하는데 사람들이 흔히 쓰는 10진수를 쓰면 자리수가 가변적이어서 오히려 더 혼란스럽다. 16진수는 각 자리수의 형태가 비슷 비슷하기 때문에 사람이 그 위치를 정확하게 기억하기 힘들다. 예를 들어 어떤 값이 0x183c7eda번지에 저장되어 있다면 사람이 이 위치를 암기하여 사용하는 것은 거의 불가능하다. 이런 값을 10개만 사용해도 사람의 머리로는 각 값을 구분할 수 없다. 즉 번지라는 것은 전혀 인간적이지 않은 기계의 값이다.

그래서 번지를 직접 사용하는 대신 좀 더 기억하기 쉬운 변수를 사용한다. 숫자로 된 번지에 별도의 이름을 붙여 놓은 것이 바로 변수이다. 사람은 숫자보다는 이름을 더 잘 기억하며 이름에 설명적인 의미를 부여할 수 있기 때문에 여러 개를 쓰더라도 구분하기 어렵지 않다. 예를 들어 1234~1237까지의 번지에 Num이라는 이름을 붙였다고 하자.

사용자 삽입 이미지
이렇게 이름을 붙여 놓으면 Num=56같이 간단하게 값을 기록할 수 있고 Result=Num같이 값을 읽기도 쉬워진다. 만약 변수라는 것이 없다면 두 값을 더해 다른 변수에 대입하고자 할 때 다음과 같은 식을 사용해야 할 것이다. 다음 표현식에서 [ ] 기호는 이 번지에 들어있는 값을 의미한다.

[0x3e98234a] = [0x3eff81a0] + [0x3d00aef6]

이런 숫자, 그것도 16진수의 나열보다는 salary=pay+bonus가 사람에게 훨씬 더 쉬우며 변수의 이름이 대상을 잘 표현할수록 더욱 쉬워진다. 컴파일러는 변수가 실제 어떤 번지를 가리키는지를 기억하고 있다가 이 변수를 사용하면 실제 번지에 값을 읽거나 쓰는 코드를 대신 작성해 준다. 흔히 변수는 값을 저장하는 상자에 비유되곤 한다. 상자에 물건을 넣어 두듯이 변수를 하나 만들어 놓으면 여기에 값을 저장하거나 다시 꺼내올 수 있다.
사용자 삽입 이미지
변수는 C언어의 구성 요소 중에 명칭으로 분류된다. 그래서 명칭을 작성하는 일반적인 규칙대로 자유롭게 작성할 수 있다. 키워드는 쓸 수 없고 영문, 숫자, 밑줄 문자로만 구성되어야 하며 대소문자를 구분한다. 이런 문법적인 제약 외에도 변수명을 작성하는 일반적인 몇 가지 법칙이 있다.

의미를 잘 설명할 수 있는 이름을 주는 것이 좋다. 사람의 이름을 기억한다면 Name이라는 이름을 쓰는 것이 좋고 평균값을 기억하는 변수에는 Average, 위치를 기억한다면 Position 같은 이름을 준다. a, b, ttt 같은 의미없는 이름을 쓰는 것도 물론 가능은 하지만 변수의 수가 많아지면 변수끼리 구분하기 어려워진다.

변수명의 길이에는 제약이 없지만 3~10자 내외로 작성하는 것이 좋다. Num, TotalScore, NowStage 등이 좋은 예이다. Highest_Score_Of_Today와 같이 변수명을 길게 쓰면 의미를 분명하게 나타낼 수는 있지만 변수명을 기억하기 어려워지고 오타를 입력할 가능성이 많아져 바람직하지 않다.

대소문자 구성을 일관되게 하는 것이 좋다. C언어는 대소문자를 구분하므로 Score와 score는 다른 변수이다. 모두 소문자로 쓰든지 아니면 첫 문자만 대문자로 쓰든지 자신만의 규칙을 정하고 그대로 따르는 것이 좋다. 선언할 때는 Score라고 해 놓고 쓸 때는 score라고 쓰면 이 변수는 선언되지 않은 것으로 에러 처리된다.

변수명은 보통 짧은 영어 단어를 활용한다. 한글 변수명은 사용할 수 없지만 원한다면 한글같은 변수명을 사용할 수는 있다. JumSoo, Saram, Juso 같은 식으로 작성해도 된다. 좀 어색하기는 하지만 영어 실력이 부족해서 이런 변수명이 더 기억하기 쉽다면 그렇게 하는 편이 좋다. 다른 변수와 구분 가능하고 의미를 쉽게 알 수 있으므로 명칭의 요건은 제대로 만족하는 것이다.

처음 실습을 할 때는 편의상 a, b, i같은 짧은 변수명을 즐겨 사용하지만 실무에서는 적절한 변수명을 붙이는 것이 아주 중요하다. 좀 쓸만한 프로그램을 만들어 볼려면 수백개나 되는 변수가 필요한데 이 변수들에 아무렇게나 이름을 붙여 놓으면 정말 힘들어진다. 더구나 여럿이 같이 하는 팀 프로젝트의 경우 내맘대로 성의없이 이름을 붙이면 팀원들에게 왕따를 당하는 수가 있으며 시간이 지난 후 자기 스스로도 코드를 파악하기 어려워진다. 간단 명료한 이름을 붙이는 것은 생각보다 훨씬 더 중요하며 또한 어려운 기술이기도 하다.
Posted by 테티스
,