여치의 프로그래밍 강좌 #3

조회 수 35348 추천 수 251 2005.07.27 23:35:38
/*
과거 모 잡지에 연재했던 프로그래밍 강좌입니다.
퍼가실땐 사전에 동의를 얻으시기 바랍니다.
-유영천
*/

지난회에서 간단한 소스를 컴파일 해보았다. 이번 회에서는 그 소스를 대충 분석해보고 C의 기초적인 문법을 알아보자.
강좌원고를 쓸때마다 약간 회의적인 것은 과연 몇분의 독자들이 이 강좌에 흥미를 가져주실것인가..하는 것이다. 단 한분이라도 흥미를 가지고 읽어주신다면 가치는 충분하다 생각하지만, 그럼 또 이 강좌를 읽는 분들에게 얼마만큼의 지식을 전달 할 수 있을것인가?
책 반권 분량의 내용을 짧은 지면에 다 싣기는 불가능하다. 따라서 기본적인 내용만을 싣는다. 만약 하고자 하는 마음이 있다면 이 정도 지식만으로도 다른 이들의 소스를 분석해가며 금방 실력을 향상시킬 수 있다고 본다. 엄청난 분량의 자료들은 서점에,인터넷에 널려있으니까.
더 발전할 수 있도록 기초적인 지식을 전달해주고, 그보다 더 중요한 흥미를 유발시켜주는 것이 관건이란 결론을 얻었다. 이런 맘을 이해해주시고 즐겁게 읽어주시기를 부탁드린다.

기본 지시어 및 규칙
-preprocessor(전처리기)
헷갈릴 부분이니 많은 얘기는 않겠다. 일단 #include만 생각하라. 여러분이 필요로 하는 기능들을 이것저것 종류별로 모아놓은 것이 라이브러리(lib파일로 되어있다.dll도 사용하지만 컴파일할땐 lib가 필요하다)이고 그것을 프로그그래밍할때 가져다 쓸 수 있게 선언해둔 것이 헤더 파일이다. *.h 파일이고 이 놈들을 갖다 쓰기 위해 #include지시어를 사용한다. 이렇게 앞에 #이 붙는 놈들이 전처리기이다. 일단은 #inlclude가 이런데 쓰는놈이라는 정도만 알아두면 되겠다.

;
C/C++에서 모든 라인의 종결에는 ; 를 사용한다. 이것으로 한 라인을 종결한다. struct나 class등 선언에 사용하는 {}의 뒤에도 ;를 붙인다. 단 반복문이나 분기문에 사용하는 {} 뒤에는 붙이지 않는다.

주석문
주석문,설명문이라고도 한다. 코드를 짜다보면 몇 만 라인씩 넘기는 일이 허다하다. 한동안 손을 놓고 있다가 나중에 이런 코드들을 보면 무슨 소린지 하나도 모른다. 하물며 다른 사람이 볼때는 더더욱 모른다. 그래서 설명을 달아놓는것이다. 그 설명을 달기 위한 지시어가 //과 /* */ 이다. //은 지시어 다음의 한줄을 주석처리하고 /* */은 안의 내용을 주석 처리한다. 주석처리된 내용은 컴파일러가 무시하고 컴파일하지 않는다.

산술 및 논리연산자
여러분이 키보드에 있는 문자가지고 표현할 수 있는 산술식. 그것이 전부이다. C/C++뿐 아니라 거의 모든 프로그래밍 언어가 그러하다. 헤괴한 문자를 사용해서 수식을 표현하는 경우는 거의 없다. 일부 논리 연산자를 제외하고는 보자마자 무슨 식인지 금방 알 수 있다.제곱같은건 따로 없어서 곱하기를 두 번 해주거나 제곱함수를 사용한다.
알만한건 빼고 헷갈릴만한것들만 적어놓겠다.
a = b -> a에 b를 대입한다.
a == b -> a와 b가 같다.같다
a <= b  -> a가 b보다 작거나 같다.
a >= b  -> a가 b보다 크거나 같다.
a < b  -> a가 b보다 작다.
a > b  -> a가 b보다 크다.
a++  -> 1증가. a = a + 1
a--  -> 1감소. a = a - 1
a +=b  ->  a = a + b
a -= b  -> a = a -b
a *= b  -> a = a * b
a /= b  -> a = a / b
a << n  -> b자리만큼 왼쪽으로 쉬프트. 즉 2의 n승만큼 곱함.
a >> n  -> b자리만큼 오른쪽으로 쉬프트. 즉 2의 n승만큼 나눔.
a | b  -> a OR b
a & b  -> a AND b
~a -<  -> NOT(a)


변수
코드로 다룰 재료가 데이터다. 개념적으로 볼때 이러한 데이터를 담을 수 있는 그릇이 변수다. 좀 더 정확히 말하자면 데이터를 담을 수 있는 일정 단위의 레지스터나 메모리를 뜻한다.변수는 몇가지 타입이 있는데 다음과 같다.

정수형
int : 4바이트 데이터 타입 .표현 범위는 -2147483648부터 2147483647 까지다.
short : 2바이트 데이터 타입. 표현범위는 -32768부터 32767 까지다
char : 1바이트 데이터 타입. 표현범위는 -128부터 127까지. ASCII 문자 코드와 그대로 매치된다. 따라서 각종 프로그래밍 툴에선 char타입인 경우 해당하는 문자로 보여주는게 일반적이다.
long : 현재는 int와 내부적으로 구분은 없다.

부호없는정수형
unsigned int: UINT라고도 한다. 역시 4바이트 데이터 타입으로서 0부터 4294967295 까지 표현할 수 있다.

unsigned short : WORD타입이라고도 한다. 2바이트 데이터 타입으로 0부터 65535까지 표현할 수 있다.

unsigned char : BYTE타입이라고도 한다. 1바이트 데이터 타입으로 0부터 255까지 표현할 수 있다. 8비트 이미지를 다룰때 이 타입을 많이 사용한다.
실수형
정수형 데이터 타입은 소수점 숫자를 표현할 수 없다. 따라서 float타입을 사용한다.float는 4바이트 부동소수점 데이터 타입이다.

포인터
메모리의 주소를 다루는데 사용하는 데이터 타입. 기본적으로는 4바이트 부호없는 정수형과 같다. 당연한 얘기지만 32비트 컴퓨터에서 메모리 주소의 범위는 0부터 2의 32승(4294967295)까지다.
부호없는 정수형과 뭐가 다른점은
1. 포인터는 컴파일러에 의해 타입 체크가 이루어진다.
2. 컴파일러에 의해 몇 가지 산술 연산은 제한된다.
3. ++과 -- 사용시 1을 더하거나 1을 빼는게 아니고 해당하는 포인터가 가리키는 데이터 타입의 사이즈만큼을 뺀다.
1,2번은 일단 그러려니 하고 넘어가면 될거고 3번은 주의깊게 봐야한다.
다음의 예문을 보자
DWORD* pdwImage = NULL;
pdwImage++;
이렇게 하면 pdwImage의 값은 1이 아닌 4가 된다. 왜냐? DWORD가 4바이트 타입이니까. 4바이트 타입을 가리키는 포인터이기에 1 증가하는게 4씩 건너뛴다는 것이다.
엄밀히 말해 포인터에 이러한 기능이 없었다고해도 프로그램 짜는게 큰 지장은 없다. 단지 약간 불편할뿐.
포인터에 대해서는 나중에 집중적으로 다룰 것이다.

최소한 1개의 함수를 포함한다.
함수에 대해서는 이후에 자세히 다루겠다. 일단 간단히 설명하자면 중고등학교 수학 교과서에 나오는 함수와 거의 같은 개념이라 할 수 있다. y = f(x) 뭐 이런식으로 뭔가 입력을 하면 결과가 튀어나오게 되는 블랙박스 같은 것이다.물론 그 블랙 박스를 우리가 짤 경우는 블랙박스는 아니다. 내용을 알고 있으니까.  엄청난 수학 공식을 함수 하나로 정의해 두고 입력값이 뭐가 들어가면 뭐가 나온다.라고 전제를 붙이는 것처럼 우리도 자주 쓰이는 복잡한 코드 루틴을 함수로 만들어두고 반복 사용할 것이다. 기본적으로 그런 용도로 쓰인다. 자주 쓰이는 코드를 반복사용하기 위한 코드의 집합이라고 생각해두면 되는것이다.
단 main()함수는 그런 용도는 아니다. C자체가 함수로 이루어진 언어다보니 규칙이 그러하다. 최소한 main()함수 한개는 있어야한다. 물론 라이브러리로 만들것이라면 main()함수는 없어도 된다. 그래도 코드를 단 한줄이라도 구현하기 위해선 어떤 함수든 적어도 한개는 있어야한다.  코드를 컴파일해서 exe파일이 만들어지게 되면(exe는 pe파일의 한 종류라고 미리 설명했었다) pe헤더에 main()함수가 위치하고 있는 어드레스의 상대번지가 코드 엔트리 포인트로 기록된다. exe가 로드되고 실행되면 pe헤더에서 이 주소를 읽어 main()함수부터 실행하게 되는 것이다.

선언부, 코드부
최소한 한개의 함수는 있어야 코드 구현이 가능하다 했다. 코드가 무엇인지는 1회 강좌때 설명했었다. 이 함수 안에다 코드를 죽 써놓게 되는데, 이 때 또한 규칙이 있으니 원칙적으로 C에서는 선언부와 코드부를 구분한다. 선언이라 함은 함수와 변수의 선언을 말한다. 보다보면 차차 알게 될 것이니 일단 선언에 대해서는 변수를 선언해놓고나서 코드에서 변수를 사용할 수 있다는 정도로 이해하면 되겠다.C++문법에서는 코드부 중간중간에 변수를 선언해도 상관없다. 선언이라 하는 것이 함수 안에서는 변수사용을 위한 스택공간을 확보하는것이다보니 컴파일 하면 자동으로 함수 진입시에 처리하는 코드로 바뀐다.C에서든 C++에서든. 일단 그러려니 하고 넘어가자.


다음의 스샷에서 이 지시어들과 규칙을 찾을 수 있다.

sample_code.jpg



구조체
개념적으로 볼때 이것도 변수의 일종이라 할 수 있다. 차이점이라면 기본적인 단위 데이터타입을 조합해서 정의 한다는 것.
구조체 안에 포함되는 변수(데이타타입)들은 연속적으로 메모리 위에 존재하게 된다. 구조체를 또 구조체 안에 포함시키면 이 구조체들 역시 연속적으로 존재하게 된다.
구조체 내의 각 필드들을 억세스하기 위해  .이나 ->(포인터인 경우)를 사용하게 된다.
구조체를 사용한 예제 소스 코드와 결과는 다음과 같다.

struct_sample_code.jpg



배열
구조체를 포함하여 정의된 모든 데이터 타입들은 배열로 구현 가능하다. 배열이란 번호를 붙여 연속적으로 배치한 데이터 타입이다. 구조체 내의 필드(변수)들의 사이즈는 불규칙하지만 배열 한칸 한칸의 사이즈는 모두 동일하다.그 때문에 숫자로 정확하게 찾아낼 수 있는 것이다. 사이즈가 규칙적이니까 인덱스*한칸 사이즈 하면 정확한 어드레스가 나온다.



배열의 메모리 맵은 다음과 같다.

array.jpg




배열의 예제코드와 그 결과는 다음과 같다.

array_sample_code.jpg




이 정도가 최소한의 문법 및 룰이다. C는 문법이 간단해서 뭐 별로 어렵다 느낄만한 부분은 없을것이다. 포인터가 나오면 다소 헷갈리겠지만 여기까진 어렵지 않다.
기본적인 설명을 했으니 이제 난 강좌에서의 예제 소스 코드를 분석해보자.

예의 그 코드에 주석을 달아보았다.

#include <stdio.h>
#include <conio.h>


int main()
{
        int                a,b,c;        // 이곳이 선언부!!


        /* 이곳부터 코드부이다. */
        a = 0;                        // 4바이트 타입 int변수 a에 0을 대입
        b = 100;                // 4바이트 타입 int변수 b에 100을 대입
        c = 100;                // 4바이트 타입 int변수 c에 100을 대입
        a = b + c;                // b와 c를 더한 값을 a에 저장

        /* 화면에 결과를 출력*/
        printf("움화화화화...나는 Hello World로 시작하지 않는다!!!\n");
        printf("%d + %d = %d\n",b,c,a);
        _getch();

        return 0;
}

#include 문이 두개 보인다. 여기서 사용한 stdio.h파일과 conio.h파일은 ANSI C에서 아주 자주 사용하는 라이브러리의 헤더 파일이다. printf()함수를 사용하기 위해 stdio.h를, _getch()함수를 사용하기 위해 conio.h를 include했다.

위의 규칙에서 설명했듯 main()함수로 시작한다.
시작하자마자 선언부가 보인다. 그리고 그 옆에는 한줄을 주석처리하는 //를 사용해 주석을 달았다.
그 아랫줄부터 코드부이다. 여러줄을 묶어서 주석처리할 수 있는 /* */을 이용해 주석을 다는 예제를 보였다. 안의 내용은 너무나 뻔하니 굳이 설명이 필요없을줄로 안다. C의 기본적인 연산자들만 사용해서 100+100을 계산하는 과정이다.

그 밑은 결과출력. printf()는 화면출력을 위한 함수인데 사용법이 꽤 까다로우므로 나중에 표준라이브러나 함수부분에서 따로 설명하겠다. 그냥 저런식으로 화면에 출력하는구나 생각해주면 되겠다. _getch()함수는 키보드로부터 한글자 입력을 받는 함수이다. 한글자 입력을 받을때까지 대기하고 있다. 저걸 안해주면 f5를 눌러서 디버그 모드로 결과를 볼때 결과가 나오자마자 창이 닫혀버린다. 결과를 충분히 볼 수 있도록, 키보드 누를때까지 대기하도록 하기 위해 사용했다.


flow control
여기까지 사용한 기능들을 이용해서 대충 뭔가 하는 코드를 짤 수 있다.
그러나 컴퓨터는 단순하다. 이 기능들만 사용해가지고는 완전 직선적인 프로그램밖에 나오지 않는다.
몬스터가 플레이어를 쫓아가는데 그냥 무작정 직진만 한다면? 당신이 옆길로 빠지면 그 놈도 옆길로 방향을 틀어 쫓아와야한다. 즉 플레이어가 직진하느냐 옆길로 새느냐에 따라 각각 다른 행동을 해야만 하는 것이다.
이것은 개념적으로 다음과 같이 표현할 수 있다

if (플레이어가 옆길로 샌다)
{
        // 참이면...
        몬스터도 방향을 튼다
}
else
{
        // 그렇지 않으면...
        계속 가던 방향으로 간다
}
이것이 flow control이다. 프로그램의 흐름은 조건에 따라 바뀌게 되는 것이다.
흐름제어는 ‘비교’와 ‘분기’에 의해 이루어진다.
실제 C/C++코드로 예를 들어보자.

C/C++에서는 if를 비롯한 몇가지 지시어로 비교를 수행하고 그에 딸린 {}안에 분기문을 채워넣는다.

int a = 0;
if (a)
{
        a = 0;}
else
{
        a = 1;}
억수 간단한 코드다.  a가 참이라면, 즉 0이 아닌 값이라면 a에다 0을 집어넣고 a가 거짓, 즉 0이라면 a에 1을 넣는 코드이다. 아주 쉽다.
여기서 if (a)절은 비교문이다.
그 밑에 {}로 채워진 두 파트는 각각의 분기하기 위한 코드들이다.
실제 메모리 상에는 순서대로 코드가 배치되어있다.

다음을 보자
보기 편하게 하기 위해 임의로 세 부분을 갈라놨다.

int a = 0;
__asm
{
        mov        eax,dword ptr[a]
        cmp         eax,0
        jz        lb_set_a1

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
lb_set_a0:
        xor        eax,eax
        mov        dword ptr[a],eax

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
lb_set_a1:
        inc        eax
        mov        dword ptr[a],eax
}
위의 C코드를 간단하게 인라인 어셈블리로 구현한 것이다. 비교하기 위해 eax레지스터에 a의 값을 읽어온다. cmp명령으로 0과 비교한다. 그 다음이 분기명령이다. jz는 이전의 산술연산의 결과가 0이라면 지정된 주소로 점프하는 명령이다. 비교라는건 엄밀히 말해서 뺄셈이다. 빼서 결과가 0이라면 같은 것, 0이 아니라면 다른 것이다. 따라서 cmp명령의 결과 zero flag레지스터가 0이거나 0이 아니거나 둘중 하나로 세팅된다. 같으면 0으로 세팅된다.
보는 바와 같이 비교한 결과에 따라 각각 다른 코드로 ‘점프’하게 되는 것이다. C/C++문법상 {}로 묶어 표현하지만 실제로는 jmp, 즉 C/C++문법으로는 goto지시어를 포함하고 있는 것이다.


반복문
(for, while)
우선 예제를 보자.
// 1부터 100까지 합을 구하는 코드
int s,i;
s = 0;
for (i=0; i<100; i++)
{
        s += i; // s=s+i;}
이 코드는 1부터 100까지 합을 구하는 코드이다. 필자는 새로운 언어를 배울때마다 1부터 100까지 합을 구하는 코드를 짜는 버릇이 있었다. 어떤 언어든 1부터 100까지 합을 구하는 프로그램을 짜게 되면 그 다음부턴 남의 소스를 분석해가는것이 가장 현실적인 학습방법이라고 생각한다.
반복문은 내부적으로 if를 포함하고 있다. 더 정확히는 어셈블리의 cmp명령을 포함하고 있다. cmp대신 loop명령을 사용할수도 있다.
반복문이라고 해서 if,else와 다른게 아니고 if,else를 응용한 것이라 보면 된다. 물론 C의 탈을 쓴 채로는 절대 티가 안나지만...어셈블리로 보면 결국 그 놈이 그놈이다.

내부적으로 if를 포함하는 부분은 for..로 시작하는 첫줄이다.
for (i=0; i<100; i++)
첫 번째 절은 초기설정이다. i변수는 0부터 시작한다. 두 번째 절은 반복을 하기 위한 조건이다. 즉 i가 100보다 작은값이면 {}안의 코드를 계속해서 반복한다는 뜻이다. 마지막 절은 증가치를 뜻한다. i가 0인상태로 머물러 있다면 언제나 100보다 작으니까 영원히 {}안의 코드를 반복해서 수행하게 될 것이다. i값이 증가를 해야 언젠가 100에 닿을 것이고 100이 되면 이 반복구문을 빠져나갈 수 있는 것이다.
그러니까 이걸 if로 바꿔보면...

        int         i,s;
        i = 0;
        s= 0;

lb_loop:
        if (i>=100)
           goto lb_exit_loop;

        s += i;
        I++;
        goto lb_loop;

lb_exit_loop:
        

이와같다.

인라인 어셈블리로 바꿔보면...
int        s = 0;
__asm
{
        xor                ecx,ecx
        xor                edx,edx

lb_loop:
        inc                ecx
        add                edx,ecx

        cmp                ecx,100
        jnz                lb_loop

        mov                dword ptr[s],edx}

for문은 n회 반복하는 형태의 루프를 구현할 때 많이 사용한다.

비슷하게 많이 사용되는 루프 지시어로는 while()문이 있다. 역시 내부적으로 if, 어셈블리 명령으로는 cmp를 사용하므로 메카니즘 자체는 for()문과 같다. 이 부분은 직접 찾아보시기 바란다. for문을 while처럼, while을 for문처럼 사용 가능하니까 for문을 사용할 수 있다면 while도 쉽게 사용할 수 있다.

이번 회에는 기초적인 C/C++문법과 몇 가지 지시어를 알아보았다. 지면의 제한이 있기에 자세히 설명하지는 못했다. 사실 VC++프로젝트를 만들어서 소스를 추가하고 컴파일 할 수 있다면 이런것들은 아무것도 아니다. 의외로 많은 사람들이 문법이나 포인터에 막혀서 포기하기보다 최초의 컴파일을 못해서 포기한다. 이번 강좌의 내용들은 여러분이 직접 학습하기 위한 목차나 지침 정도로 생각해주면 되겠다.

다소 지루하고 재미없는 내용들의 연속이었을지 모르겠다. 그렇다해도 재미없는데다가 난해하기까지 한 강좌밖에 쓸 수 없는 필자로선 어쩔 도리가 없다. 어차피 중요한 것은 프로그래밍을 학습하는 개개인들의 마음가짐. 하고자 하는 맘이 있으면 이런 난해한 강좌도 나름대로 도움이 되리라 믿어 의심치 않는다.

다음번 강좌에서는 이번에 다룬 내용들을 가지고 여러가지 예제 코드를 짜보며 분석해보기로 하자.
파일 첨부

여기에 파일을 끌어 놓거나 파일 첨부 버튼을 클릭하세요.

파일 크기 제한 : 0MB (허용 확장자 : *.*)

0개 첨부 됨 ( / )
List of Articles
번호 제목 글쓴이 날짜 조회 수
83 여치의 프로그래밍 강좌 #6 file [1] 여치 2005-07-27 29846
82 여치의 프로그래밍 강좌 #5 file 여치 2005-07-27 42032
81 여치의 프로그래밍 강좌 #4 file 여치 2005-07-27 39350
» 여치의 프로그래밍 강좌 #3 file 여치 2005-07-27 35348
79 여치의 프로그래밍 강좌 #2 file 여치 2005-07-27 31837
78 여치의 프로그래밍 강좌 #1 file 여치 2005-07-27 30037
77 지형도 BSP를 사용하시나요? [1] 초보 2005-07-06 26492
76 DirectX 입문용으로 적절한 책이 있을지요? [2] MiR 2005-03-01 41287
75 [re] DirectX 입문용으로 적절한 책이 있을지요? [1] 여치 2005-03-02 30297
74 BSP/Portal/PVS에 대한... guest 2005-02-18 24490
73 [re] BSP/Portal/PVS에 대한... file 여치 2005-02-19 23534
72 3D가속에 관한 질문 [3] 바하무트 2004-12-29 37321
71 [re] 3D가속에 관한 질문 여치 2004-12-29 27613
70 [질문] HeightMap의 퍼포먼스... [1] croove 2004-11-01 28868
69 [상담] 어떻게 해야할까요? . 2004-08-20 26046
68 [re] [상담] 어떻게 해야할까요? [1] 여치 2004-08-21 29021
67 [질문] 힙메모리 라이브러리에대해서. clever98 2004-08-08 32744
66 [re] [질문] 힙메모리 라이브러리에대해서. [1] 여치 2004-08-08 30295
65 [re] [질문] 단편화의 제거는 어떤식으로 하시나요? [1] 웰치스포도주스 2004-11-23 27815
64 개발 인력에 대한 질문 [1] 방문객 108 2004-07-20 23064



XE Login

天安門大屠殺 六四天安門事件 反右派鬥爭 大躍進政策 文化大革命 六四天安門事件 The Tiananmen Square protests of 1989 天安門大屠殺 The Tiananmen Square Massacre 反右派鬥爭 The Anti-Rightist Struggle 大躍進政策 The Great Leap Forward 文化大革命 The Great Proletarian Cultural Revolution 人權 Human Rights 民運 Democratization 自由 Freedom 獨立 Independence 多黨制 Multi-party system 民主 言論 思想 反共 反革命 抗議 運動 騷亂 暴亂 騷擾 擾亂 抗暴 平反 維權 示威游行 法輪功 Falun Dafa 李洪志 法輪大法 大法弟子 強制斷種 強制堕胎 民族淨化 人體實驗 胡耀邦 趙紫陽 魏京生 王丹 還政於民 和平演變 激流中國 北京之春 大紀元時報 九評論共産黨 獨裁 專制 壓制 統一 監視 鎮壓 迫害 侵略 掠奪 破壞 拷問 屠殺 肅清 活摘器官 障テ社會 誘拐 買賣人口 遊進 走私 毒品 賣淫 春畫 賭博 六合彩 台灣 臺灣 Taiwan Formosa 中華民國 Republic of China 西藏 土伯特 唐古特 Tibet 達償ワ喇嘛 Dalai Lama 新疆維吾爾自治區 The Xinjiang Uyghur Autonomous Region free tibet