1장 :: 프로그램은 프로그래밍 언어로 만들어요!
[접기]
목차
1. 우리가 다룰 것들
우리의 목표는 프로그램을 짜는 것입니다. 그런데 이 프로그램은 운영체제(대부분의 경우 윈도우) 위에서 동작하고, 이 운영체제는 다시 컴퓨터 위에서 동작합니다. 이부분에서 "윈도우랑 컴퓨터랑 다른 말이야?"라고 생각하신 분들이 있을 겁니다. 네, 이 둘은 다른말입니다. 당연히 브라우저(인터넷 익스플로러)도 다릅니다. 이 강의는 컴퓨터를 프로그래밍의 도구로서는 처음 사용해보는 분들도 보실 수 있는 걸 목표로 합니다. 그렇기에 먼저 앞으로 우리가 다룰 것들에 대해 간단히 정리하고자 합니다. 다만, 이해를 돕기 위해 일부 내용을 과도하게 단순화하였으니 잘못된 것 같거나 이상해보이는 부분은 댓글로 남겨주시면 제가 답변해드리겠습니다.
먼저, 제일 기본이 되는 요소는 컴퓨터입니다. 본체가 있고, 모니터가 있고, 마우스와 키보드가 달려있는 이 기계를 컴퓨터라고 합시다. 그리고 이 컴퓨터에 명령을 내리는 것이 윈도우나 리눅스와 같은 운영체제입니다. 그리고 운영체제에 명령을 내리는 것이 바로 우리가 만들 프로그램들입니다. 즉, 컴퓨터가 있고, 컴퓨터를 기초로 그 위에 운영체제가 있고, 또 운영체제를 기초로 그 위에 프로그램이 있습니다. 물론, 이는 정확한 정의는 아닙니다. 어느 범위까지를 프로그램이라고 부를지는 논의해볼만한 주제입니다. 예를 들어, "운영체제는 프로그램인가?"와 같은 질문을 할 수 있으니까요. 하지만, 지금은 문제를 단순화하기위해 그냥 이렇게 정합시다.
2. 프로그램의 예시
그럼 대체로 프로그램들은 어떻게 생겼을까요? 프로그램들의 예를 통해서 감을 잡아봅시다.
2.1. 인터넷 브라우저 (인터넷 익스플로러, 크롬, 파이어폭스 등)
실제로 사이트들은 HTML이라 불리는 코드로 구성되어있습니다. 예를 들어, 네이버[1]
| |
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. 프로그래밍 언어
지금까지는 프로그램들이 어떤 동작을 하는지를 높은 차원에서 살펴보았습니다. 그러나 이런 프로그램들은 공통적으로 프로그래밍 언어로 작성되어있고, 프로그래밍 언어는 대부분 매우 단순한 동작만을 수행합니다. 즉, 원자가 모여서 분자가 되고 분자가 모여서 복잡한 물질을 이루듯이, 아주 단순한 동작만 가능한 명령어들을 모아서, 복잡한 작업을 하는 거대한 프로그램을 만드는 것이 우리의 목표입니다. 프로그래밍 언어가 어떤 동작들을 할 수 있는지 예를 들어봅시다.
- 변수에 수를 저장하기 ( x = 5 )
- 두 수를 더하기 ( x = 2 + 3 )
- 변수를 더하기 ( x = y + z )
- 대소를 비교하기 ( x > y인가? )
- 조건에 따라 다른 행동하기 ( x > y 이면 x를 출력, 아니라면 y를 출력 )
- 행동 반복하기 ( "x를 출력하고 x에 1을 더하기" 자체를 10번 반복 )
3.1. 프로그래밍 언어의 종류
사람이 쓰는 말에도 한국어, 영어, 불어처럼 다양한 언어들이 있듯이 프로그래밍 언어에도 C, C++, C#, Python, Java와 같이 다양한 언어들이 있습니다. "하나만 있으면 되지 왜 여러가지가 있어요?"라는 의문이 든다면 사람들이 왜 언어를 하나로 통일시키지 못했는지 생각해보면 됩니다. 이미 쓰던 사람들이 자기 언어를 계속 쓰려는 점도 있고, 해당 지역에 필요한 표현들은 그 지역 언어가 가장 잘 가지고 있을 것이고, 언어마다 장단점이 있는 것도 이유가 될 것입니다.
이런 다양한 언어 중, 이번 강의에서 다룰 것은 C언어입니다. 많이 쓰이는 언어들 중에서는 가장 오래 발전해왔고, 쓸 수 있는 플랫폼도 다양하며, 이미 C로 만들어진 프로그램들도 많습니다. 그만큼 언어에 있어야할 기본적인 기능들은 대부분 가지고 있으며, 최적화도 잘 되어있어 속도도 빠릅니다. 물론 그만큼 내용도 많고 복잡할 수 있지만, C언어를 어느정도 공부하고나면 최근에 나오는 많은 언어들은 C언어의 기능들을 좀 더 쓰기 쉽게 간단한 버전으로 바꾼것이고, 좀 더 섬세하거나 복잡한 기능이 필요하다면 C언어의 고급 내용들을 추가로 배우게 됩니다. 즉, C언어에서 배운 내용들은 다른 언어에도 적용되는 것들이고, 언젠가 볼 일이 있는 언어이므로, 배워두어서 나쁠 건 없겠다는 마음으로 읽어주시면 고맙겠습니다.
3.2. 프로그래밍 언어의 발전
사실 처음부터 C언어, Python과 같은 언어들이 있었던 것은 아닙니다. 처음에는 0과 1만 있었습니다. 이게 무슨 말일까요? 컴퓨터는 전기 신호로 작동하는 기계이고, 전기 신호는 다음 그림[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 출력하기 |
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 출력하기 |
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 출력하기 |
그러나 여전히 복잡한 프로그램을 짜기에는 어렵습니다. 그래서 이번에는 아예 명령어들을 재설계해서 좀 더 사람의 직관에 맞는 언어를 만들었는데, 그게 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언어를 좀 더 익힌 후에 좀 더 찾아보면 재밌는 이야깃거리가 많이 있습니다.
[1] 코드 출처:https://www.naver.com/[2] 사진 출처:https://www.ck12.org/c/physics/electronic-signal/lesson/Electronic-Signal-MS-PS/