1장 :: 프로그램은 프로그래밍 언어로 만들어요!

[접기]

목차

  • 1. 우리가 다룰 것들
  • 2. 프로그램의 예시
    • 2.1. 인터넷 브라우저 (인터넷 익스플로러, 크롬, 파이어폭스 등)
    • 2.2. 게임 (롤, 배틀그라운드, 메이플스토리 등)
    • 2.3. 메신저 (카카오톡, 라인 등)
  • 3. 프로그래밍 언어
    • 3.1. 프로그래밍 언어의 종류
    • 3.2. 프로그래밍 언어의 발전


1. 우리가 다룰 것들


우리의 목표는 프로그램을 짜는 것입니다. 그런데 이 프로그램은 운영체제(대부분의 경우 윈도우) 위에서 동작하고, 이 운영체제는 다시 컴퓨터 위에서 동작합니다. 이부분에서 "윈도우랑 컴퓨터랑 다른 말이야?"라고 생각하신 분들이 있을 겁니다. 네, 이 둘은 다른말입니다. 당연히 브라우저(인터넷 익스플로러)도 다릅니다. 이 강의는 컴퓨터를 프로그래밍의 도구로서는 처음 사용해보는 분들도 보실 수 있는 걸 목표로 합니다. 그렇기에 먼저 앞으로 우리가 다룰 것들에 대해 간단히 정리하고자 합니다. 다만, 이해를 돕기 위해 일부 내용을 과도하게 단순화하였으니 잘못된 것 같거나 이상해보이는 부분은 댓글로 남겨주시면 제가 답변해드리겠습니다.

먼저, 제일 기본이 되는 요소는 컴퓨터입니다. 본체가 있고, 모니터가 있고, 마우스와 키보드가 달려있는 이 기계를 컴퓨터라고 합시다. 그리고 이 컴퓨터에 명령을 내리는 것이 윈도우나 리눅스와 같은 운영체제입니다. 그리고 운영체제에 명령을 내리는 것이 바로 우리가 만들 프로그램들입니다. 즉, 컴퓨터가 있고, 컴퓨터를 기초로 그 위에 운영체제가 있고, 또 운영체제를 기초로 그 위에 프로그램이 있습니다. 물론, 이는 정확한 정의는 아닙니다. 어느 범위까지를 프로그램이라고 부를지는 논의해볼만한 주제입니다. 예를 들어, "운영체제는 프로그램인가?"와 같은 질문을 할 수 있으니까요. 하지만, 지금은 문제를 단순화하기위해 그냥 이렇게 정합시다.

2. 프로그램의 예시


그럼 대체로 프로그램들은 어떻게 생겼을까요? 프로그램들의 예를 통해서 감을 잡아봅시다.

2.1. 인터넷 브라우저 (인터넷 익스플로러, 크롬, 파이어폭스 등)


실제로 사이트들은 HTML이라 불리는 코드로 구성되어있습니다. 예를 들어, 네이버[1]의 HTML 코드를 보면 다음과 같습니다.
HTML로 구성된 실제 사이트의 모습 브라우저가 보여주는 사이트의 모습
브라우저를 만드는 프로그래머들은 왼쪽 그림과 같은 HTML 코드를 오른쪽과 같이 이쁘게 출력해주는 프로그램을 만드는 것입니다. 좀 자세하게 보자면, HTML 코드를 읽고 각각의 문자들이 무슨 의미인지를 파악해서 화면의 적절한 위치에 적절한 요소를 배치하는 일입니다. 더 나아가서, 우리가 버튼을 클릭하면 댓글이나 아이디/비밀번호와 같이 우리가 입력한 값들을 서버로 전송하거나 새로운 페이지를 보여주기도 하고, 동영상이 원활하게 재생되도록 도와주기도 합니다.

2.2. 게임 (롤, 배틀그라운드, 메이플스토리 등)


게임에서는 방향키를 누르면 캐릭터가 움직이고, 클릭하거나 특정 키를 누르면 스킬을 사용하기도 합니다. 실제 상황을 하나 생각해보면, 우리가 캐릭터를 오른쪽으로 움직이고자 오른쪽 방향키를 누를 때, 게임 프로그램은 이를 인식하고 어떤 경우인지 판단합니다. 다른 키는 눌러진게 없고, 오른쪽에 아직 이동할 수 있는 공간이 남아있으니, 이건 캐릭터를 오른쪽으로 움직이려는 것이구나! 그리고는 캐릭터의 좌표를 조금 오른쪽으로 옮깁니다. 하지만 화면에는 아직 캐릭터가 그대로 있으므로 운영체제에게 화면을 새로고침 해달라는 요청을 합니다. (바로 여기서 프로그램이 운영체제 위에서 동작한다는 걸 알 수 있네요!) 그러면 유저가 보기에는 오른쪽 방향키를 누르면 캐릭터가 오른쪽으로 움직이는 것입니다. 실제로는 물체가 서로 부딪히거나 폭발하는 등의 다양한 물리 연산들을 수행하는데, 그렇기에 게임 프로그래머는 어느정도 물리학 지식이 필요합니다. (이번에는 프로그램을 만드는 데 학문적 지식이 왜 필요한지에 대한 예시이네요!)

2.3. 메신저 (카카오톡, 라인 등)


메신저의 주요 역할은 내가 보낸 텍스트나 이미지를 상대방에게 잘 전달해주고, 마찬가지로 상대방이 보낸 텍스트나 이미지를 나에게 잘 전달해주는 것입니다. 여기서 잘 전달한다는 말은 텍스트나 이미지가 손상되지 않는다는 의미도 있지만, 순서가 바뀌지 않아야 한다는 의미도 있습니다. 내가 A B C 순서로 텍스트를 보내더라도, 상대방에게는 B C A 순서로 텍스트가 도착할 수 있습니다. 순서가 바뀌면 의사소통이 제대로 되지 않기 때문에, 메신저 프로그램은 각각의 메시지에 시간 등을 함께 저장하고 이를 이용하여 도착한 메시지들을 올바른 순서로 정렬하여 보여줍니다.
그렇기에 메신저와 같은 프로그램을 만드려면 인터넷 통신에 대한 내용을 잘 이해하고 있어야합니다. 그리고 메시지 안에 중요하거나 민감한 내용이 포함되어있을 수 있으므로 보안에도 신경써야합니다.
모든 메시지마다 자신의 이전 메시지가 무엇인지를 함께 저장합니다. 만약 보내는 사람이 A B C D 순서로 메시지를 보냈고, 받는 사람은 A B까지는 올바르게 받았으나 이어서 D라는 메시지가 도착했다면, D 앞에 있어야할 C가 없다는 것을 알 수 있으므로 D를 화면에 표시하지 않고 조금 더 기다립니다. 그러다가 C가 도착하면 C 앞에 있어야할 B는 올바르게 받았으므로 이제 받은 메시지를 C D 순으로 표시합니다. 이 방식이 앞서 설명한 방식보다 좋은 이유는 메시지 순서를 지키기 위해 언제까지 기다려야하는 지 명확하게 알 수 있다는 점입니다. 앞선 방식에서는 A B 다음에 D가 왔다면, D보다 먼저 와야하는 메시지가 있었는지 알 수 없기 때문에 예를 들어 1초정도 기다려봐도 D보다 앞선 메시지가 오지 않는다면 D를 정상적인 순서로 보거나 하는 안전하지 않은 방식을 사용해야겠지요.

3. 프로그래밍 언어


지금까지는 프로그램들이 어떤 동작을 하는지를 높은 차원에서 살펴보았습니다. 그러나 이런 프로그램들은 공통적으로 프로그래밍 언어로 작성되어있고, 프로그래밍 언어는 대부분 매우 단순한 동작만을 수행합니다. 즉, 원자가 모여서 분자가 되고 분자가 모여서 복잡한 물질을 이루듯이, 아주 단순한 동작만 가능한 명령어들을 모아서, 복잡한 작업을 하는 거대한 프로그램을 만드는 것이 우리의 목표입니다. 프로그래밍 언어가 어떤 동작들을 할 수 있는지 예를 들어봅시다.
이런 기본적인 언어의 구조를 문법이라고 하고, 우리는 당분간 이 문법들을 살펴볼 것입니다.

3.1. 프로그래밍 언어의 종류


사람이 쓰는 말에도 한국어, 영어, 불어처럼 다양한 언어들이 있듯이 프로그래밍 언어에도 C, C++, C#, Python, Java와 같이 다양한 언어들이 있습니다. "하나만 있으면 되지 왜 여러가지가 있어요?"라는 의문이 든다면 사람들이 왜 언어를 하나로 통일시키지 못했는지 생각해보면 됩니다. 이미 쓰던 사람들이 자기 언어를 계속 쓰려는 점도 있고, 해당 지역에 필요한 표현들은 그 지역 언어가 가장 잘 가지고 있을 것이고, 언어마다 장단점이 있는 것도 이유가 될 것입니다.

이런 다양한 언어 중, 이번 강의에서 다룰 것은 C언어입니다. 많이 쓰이는 언어들 중에서는 가장 오래 발전해왔고, 쓸 수 있는 플랫폼도 다양하며, 이미 C로 만들어진 프로그램들도 많습니다. 그만큼 언어에 있어야할 기본적인 기능들은 대부분 가지고 있으며, 최적화도 잘 되어있어 속도도 빠릅니다. 물론 그만큼 내용도 많고 복잡할 수 있지만, C언어를 어느정도 공부하고나면 최근에 나오는 많은 언어들은 C언어의 기능들을 좀 더 쓰기 쉽게 간단한 버전으로 바꾼것이고, 좀 더 섬세하거나 복잡한 기능이 필요하다면 C언어의 고급 내용들을 추가로 배우게 됩니다. 즉, C언어에서 배운 내용들은 다른 언어에도 적용되는 것들이고, 언젠가 볼 일이 있는 언어이므로, 배워두어서 나쁠 건 없겠다는 마음으로 읽어주시면 고맙겠습니다.

3.2. 프로그래밍 언어의 발전


사실 처음부터 C언어, Python과 같은 언어들이 있었던 것은 아닙니다. 처음에는 0과 1만 있었습니다. 이게 무슨 말일까요? 컴퓨터는 전기 신호로 작동하는 기계이고, 전기 신호는 다음 그림[2]과 같이 대부분 물결 모양의 그래프로 나타납니다.
아날로그 신호 디지털 신호
일반적인 전기 회로에서 시간에 따른 전압을 측정해보면 왼쪽 그림과 같이 약간 울퉁불퉁한 물결파 모양의 그래프를 관찰할 수 있습니다. 예를 들어 마이크에 대고 사람이 소리를 내면 마이크에 있는 진동판이 떨리면서 이것을 전기 신호로 바꾸고, 그 때의 전기 신호가 마치 왼쪽 그림과 같이 나옵니다. 하지만 컴퓨터는 사람의 목소리와 같은 연속적인 데이터를 처리하는 장치가 아닙니다. 1과 2를 더하면 3이 되어야지 2.9나 3.1이 되면 안됩니다. 이 때, 연속적이다의 반댓말로 이산적이다라고 합니다. 즉, 컴퓨터는 이산 데이터를 처리하는 장치입니다. 그렇기에 오른쪽 그림과 같은 디지털 신호를 사용하고, 전압이 특정 수치 이상 올라가면 1, 그렇지 않으면 0으로 처리합니다. 이렇듯 경우의 수가 딱 2가지밖에 없기 때문에 컴퓨터에서는 모든 데이터를 2진법으로 나타내곤 합니다. ("컴퓨터는 2진법을 사용한다"라는 말을 얼핏 들은적이 있을텐데 이게 바로 그 이유네요!)

그럼 0과 1을 이용하여 우리가 하고자 하는 연산들을 어떻게 나타낼 수 있을까요? 두 수를 더하고, 두 수를 곱하고, 수를 어딘가에 저장하는 그런 연산들 말입니다. 컴퓨터를 만든 사람들은 이 문제를 각 연산마다 고유한 숫자를 부여해 해결했습니다. 예를 들어 가상의 미니컴퓨터를 만들어보겠습니다. 미니컴퓨터는 두 개의 변수 x와 y를 저장하는 공간이 있다고 가정합시다.
bit 0 bit 1 bit 2 bit 3 명령어 뜻
0 0 0 0 x, y를 0으로 초기화하기
0 0 1 0 x에 1 더하기
0 0 0 1 y에 1 더하기
0 0 1 1 x, y에 1 빼기
0 1 1 0 x에 y 더하기
0 1 0 1 y에 x 더하기
1 0 1 0 x 입력받기
1 0 0 1 y 입력받기
1 1 1 0 x 출력하기
1 1 0 1 y 출력하기
자세히 살펴보면 제가 명령어에 2진수를 배정할 때 약간의 규칙을 가지고 있다는 것을 알 수 있습니다. bit 0과 bit 1은 명령어의 종류(더하는 연산인지, 입력받는 연산인지 등)를 나타내고, bit 2와 bit 3는 변수(bit 2가 켜져있으면 x에 대한 연산이고 bit 3가 켜져있으면 y에 대한 연산)를 지정합니다. 그럼 이 명령어들로 사용자가 입력한 두 수를 더한다음 출력해주는 간단한 계산기를 만드려면 어떻게 하면 될까요?
bit 0 bit 1 bit 2 bit 3 명령어 뜻
1 0 1 0 x 입력받기
1 0 0 1 y 입력받기
0 1 1 0 x에 y 더하기
1 1 1 0 x 출력하기
이러면 되겠네요! 하지만 이렇게 프로그램을 짤 때마다 각 명령어가 어떤 2진수에 대응하는 지 외우고 있기는 힘들고, 어디에 표로 적어놨다고 하더라도 매 번 찾아가서면서 프로그램을 짜는 것은 굉장히 힘든 일입니다. 그래서 사람들은 이 2진수와 1대1로 대응되는 영어 단어들을 만들고 이를 어셈블리어라는 새로운 언어로 만들었습니다. 우리의 미니 컴퓨터에서 예를 들면 다음과 같습니다.
bit 0 bit 1 bit 2 bit 3 기호 명령어 뜻
0 0 0 0 INIT x, y를 0으로 초기화하기
0 0 1 0 INCX x에 1 더하기
0 0 0 1 INCY y에 1 더하기
0 0 1 1 DECA x, y에 1 빼기
0 1 1 0 ADDX x에 y 더하기
0 1 0 1 ADDY y에 x 더하기
1 0 1 0 INPX x 입력받기
1 0 0 1 INPY y 입력받기
1 1 1 0 OUPX x 출력하기
1 1 0 1 OUPY y 출력하기
INCX는 INCrease X를 줄인 것이고, INPX는 INPut X를 줄인 것입니다. 이렇듯 조금 더 사람이 이해하기 쉽게 2진수를 알파벳 단어로 치환한 것이 어셈블리어입니다. 실제로 코딩을 할 때에는 어셈블리어로 프로그램을 작성한 후, 어셈블리어라는 프로그램에 넘겨주면 이를 다시 2진수로 바꿔줍니다. 그럼 이제 컴퓨터가 이해할 수 있는 (하지만 사람은 이해하기 힘든) 코드가 완성됩니다. 중간 단계가 하나 늘었지만 사람이 보기에는 훨씬 편해졌습니다.
그러나 여전히 복잡한 프로그램을 짜기에는 어렵습니다. 그래서 이번에는 아예 명령어들을 재설계해서 좀 더 사람의 직관에 맞는 언어를 만들었는데, 그게 C언어입니다. C언어로 두 수의 합을 입력받아 출력하는 프로그램은 다음과 같이 생겼습니다.

#include
int main() {
int x, y;
scanf("%d %d", &x, &y);
printf("%d", x + y);
return 0;
}
1, 2, 6, 7번 줄은 모든 프로그램에 존재하는 공통적인 부분이니 지금은 신경쓰지 않아도 되고, 실제 프로그램의 동작을 정의한 3, 4, 5번 줄을 봅시다. 3번 줄은 변수 x와 y를 만들고 정수만 들어갈 수 있도록 지정합니다. 4번 줄은 x와 y에 각각 사용자가 입력한 수를 넣습니다. 5번 줄은 x + y의 값을 다시 사용자에게 출력합니다.

C언어의 구조는 어셈블리어와 많이 다른 것을 볼 수 있습니다. 자세한 것들은 이 강의에서 배워나갈테니, 지금은 어떤 과정을 거쳐서 C언어라는 것이 등장했고, 각각은 대충 어떻게 생겼구나 정도로만 이해해둡시다. 나중에 C언어를 좀 더 익힌 후에 좀 더 찾아보면 재밌는 이야깃거리가 많이 있습니다.