C - 1.1. 시작

목차

1. 시작

이번에 여름방학을 맞아 초심으로 돌아가 C언어를 복습하면서 블로그에 그 내용을 정리하기로 했다. 다만 복습하면서 쓰는 것이므로 프로그래밍을 완전히 처음 시작하는 사람이 보기에는 배려가 부족할 수 있다.

교재는 흔히 C언어의 바이블 중 하나라고 꼽히는 K&R을 사용할 것이며 내가 지금까지 주워들었던 지식들도 중간중간 서술할 예정이다. 책 내용을 마무리하고 나면 링크드 리스트 등의 자료구조나, C언어로 구현할 만한 간단한 프로그램 등을 추가로 쓸 것이다.

이때 K&R에서는 터미널에서 컴파일하는 방식으로 가르치고 있으므로 나는 wsl에서 돌아가는 Ubuntu 터미널을 사용하여 글의 코드들을 실행할 것이다. 에디터로는 vscode를 사용할 것이다.

만약 당신이 특별히 사용하는 에디터나 IDE가 없다면, 흔히 C언어를 처음 시작할 때 사용하는 비주얼 스튜디오를 사용해도 좋을 것이다.

2. C언어의 구성

컴퓨터는 기본적으로 우리가 지시하는 연산을 순서대로 처리할 뿐인 기계이다. 그리고 C언어는 컴퓨터에게 우리가 원하는 연산을 지시할 수 있는 도구 중 하나이다. 이때 우리가 C언어로 내리는 지시는 얼마나 복잡한 지시건에 상관없이 함수(function)와 변수(variable)들로 이루어진다.

그럼 그 함수와 변수란 무엇일까? 함수는 어떤 작업과 어떤 연산을 할 것인지를 컴퓨터에 알려주는 문(statement)들로 구성되어 있는 요소이다. 그리고 변수는 그런 작업에 필요한 값들을 저장하고 있다. 개념만 설명하니까 굉장히 어려워 보인다. 쉬운 이해를 위해 예시를 들어 보자.

1+2를 계산한다고 생각해 보자. 거의 누구나가 3이라고 대답할 수 있을 것이다. 하지만 이를 뜯어서 생각해 보면 우리는 덧셈이라는 2항 연산을 1과 2를 대상으로 실행한 것이다.

즉 덧셈이라는 작업을 지시하는 것이 함수이고, 그 대상이 되는 값인 1과 2가 변수에 해당한다. 이런 식으로 변수에 있는 값들을 이용해서 함수에서 지시하는 작업을 하는 것이 바로 C언어 프로그램이다.

그러면 이제 긴 문법 설명을 하기 전에 먼저, 직접 프로그램을 작성해 보자.

3. 첫 프로그램

우리가 처음 작성할 프로그램은 hello, world를 출력해 주는 것이다. 일단 에디터에서 다음 문장을 따라 쳐서 hello.c라는 이름으로 저장해 주자.

#include <stdio.h>
 
main()
{
    printf("hello, world\n");
}

NOTE

C언어를 조금 배워본 사람이라면 위 코드를 보고 이상하게 여길 수 있다. main함수의 반환값 자료형이 없다는 이유에서이다. 심지어 main함수의 리턴값도 없다. 하지만 C가 처음 나올 당시의 표준에 의하면 `implicit int rule` 에 따라 반환값 자료형이 명시되어 있지 않은 함수의 반환형은 암묵적으로 int로 받아들인다. 이 문법은 C99 표준에서부터 폐기되었다. 하지만 많은 컴파일러에서 여전히 잘 돌아간다.

그리고 아직 함수가 정확히 무엇이고 어떻게 작성되는지도 쓰지 않았다. 그런 상황에 반환형에 관련된 서술을 하는 것은 시기상조인 듯 하여 처음에 받아들이는 정보량을 좀 줄이기 위해 이런 코드를 작성하였다.

정리하자면, 함수의 반환값의 자료형이 명시되어 있지 않은 경우 반환값의 자료형이 int인 것으로 컴파일러에서 받아들이기 때문에 위의 코드는 문제가 없다. 또한 함수의 반환값이 없는 것도 문제가 되지 않는다. 함수의 반환값이 없을 경우 자동으로 0을 반환해 주기 때문이다.

 


그리고 나서 이를 gcc가 설치된 터미널에서 gcc hello.c 로 컴파일하고 ./a.out을 열어보면 hello, world 가 나오는 것을 볼 수 있다. 뭔가 나오긴 하는 것 같은데 대체 어떤 규칙에 따라 돌아가는 것인지 알 수가 없다. 한 줄씩 분석해 보자.

4. 첫 프로그램에 대한 설명

#include <stdio.h>

이 줄은 컴파일러에게, 표준 입출력 라이브러리(stdio는 standard input/output의 약자이다)를 쓰겠다고 알려 주는 것이다. 입출력 함수를 쓰게 해 주는 역할을 하는 부분이라고 생각해 주면 된다.

main()

C언어 프로그램의 실행은 언제나 메인함수부터 시작한다. 어떤 구조로 코드를 짜던지 간에 코드의 실행은 메인함수의 내용부터 실행된다. main의 내용 외에 다른 함수 내부에 있는 코드가 먼저 실행된다든지 하는 일은 없다.

이는 main이라는 이름의 함수에 대해 정해진 규칙이다. 따라서 일반적으로 함수의 이름은 자유롭게 정할 수 있지만 main이라는 이름은 예외이다. 즉 이 줄은 프로그램이 실행하는 내용의 시작을 알리는 것이라고 생각하면 된다.

또 함수의 내용은 함수 이름 뒤에 오는 중괄호 내부에 있다. 따라서 main() 뒤에 오는 중괄호 내부의 내용이, 프로그램이 실행하는 문(statement)이다. 그런데 main은 함수 이름이라고 치고, 그 뒤에 오는 소괄호는 뭘까?

그건 함수의 인자(argument)를 뜻한다. 함수들 간에 정보를 주고받는 방식은 함수 호출시에 인자를 전달하는 방식이다. main함수도 함수이므로 int main(int argc, char* argv[]) 등으로 main함수에 인자를 줄 수도 있다. 이런 방식은 나중에 보도록 하자.

printf("hello, world\n"); 함수 printf에 인자 "hello, world\n"을 전달하면서 호출한다. 이때 printf는 <stdio.h> 에 포함되어 있는 출력 함수이다. 인자로 받은 format string을 출력하는 것인데, 자세한 내용은 나중에 다루고 지금은 그냥 출력할 것을 인자로 받아서 출력해 주는 함수라고 생각하면 된다.

다만, 코드에서 이렇게 한 문장을 끝낼 때 세미콜론을 붙여 준다는 것만 주의깊게 보자. C언어에서 세미콜론은 자연어 문장에서의 마침표와 비슷한 기능을 한다.

5. 이스케이프 문자

위 코드의 "hello, world\n" 내에 있는 \n은 줄바꿈을 뜻한다. 줄바꿈 같은 문자는 쉽게 표현할 수 없으니 \를 붙여서 따로 정의하는 것이다. 만약 \n없이 프로그램을 실행하면 출력된 hello, world뒤에 줄바꿈이 없어지는 것을 볼 수 있을 것이다. 이때 이러한 \를 붙여서 따로 정의해 주는 문자들을 이스케이프 문자라고 한다.

C언어에서 이스케이프 문자를 사용하지 않고 줄바꿈을 표기할 수 있는 방법은 없다. 반드시 \n을 사용해서 표기해 주어야 한다. 만약 문자열 내에 줄바꿈을 그대로 넣어 주겠다는 생각으로 다음과 같은 코드를 짜서 실행한다면 바로 에러 코드를 보게 될 것이다.

printf("hello, world
");

물론 이스케이프 문자보다는 그냥 엔터키로 줄바꿈을 넣어 주는 것이 직관적이다. 따라서 좀더 최신의 언어들은 Python의 삼중 따옴표나 Javascript의 템플릿 리터럴처럼, 줄바꿈을 그대로 출력해 줄 수 있는 방식을 지원하기도 한다. 하지만 C같은 고전적인 언어에서는 그런 것을 지원하지 않는다. 이스케이프 문자밖에는 방법이 없다.

줄바꿈 외에도 탭(\t)이나 백스페이스(\b)와 같은 다른 이스케이프 문자들도 있다. 이스케이프 문자들에 대해서는 나중에 제대로 다룰 것이니 지금은 그런 것이 있다는 정도만 인식하고 넘어가면 된다.

6. printf의 출력

printf는 절대 자동으로 줄바꿈을 넣어 주지 않는다. 인수로 받은 문자열에 어떤 것도 추가하지 않고 그대로 출력해줄 뿐이다. 다소 고지식하게 느껴지기도 한다.

그러나 반면에 이런 점을 이용해 printf를 여러 번 호출하여 하나의 문자열을 나눠서 출력하는 것도 가능하다. 하나의 문자열을 여러 번의 printf를 이용해 나눠서 출력하는 방식의 코드를 쓰면서 첫 글을 마친다. 다음 코드를 실행할 시, hello, world\n 가 아까와 같이 잘 출력되는 것을 볼 수 있을 것이다.

#include <stdio.h>
 
main()
{
    printf("hello, wor");
    printf("ld\n");
}