2016년 4월 28일 목요일

저번 강좌 에서는 C프로그램의 기본적인 구조를 이해하셨으리라 봄니다.이번 강좌 에서는 C프로그램의 구조를 좀더 자세히 살펴보도록 하겠습니다.

1. C 프로그램의 구성 요소
C프로그램을 구성하는 요소들에 대해 알아보도록 하죠.
C프로그램을 구성하는 요소에는 키워드, 심볼, 문장, 블럭등이 있습니다.

(1) 키워드
키워드는 저번 강의때 간략히 설명을 했었는데, 더 정확히 말하자면 C 컴파일러가 특별한 의미로 인식하는 단어를 말합니다.
다른 단어들과는 달리 특별한 기능을 수행하게 되죠.
C언어 키워드는 다른 언어에 비해 적은 편 입니다.
이유는 C언어 키워드에는 표준 입출력에 관한 키워드가 들어있지 않기 때문이죠.
단지 데이터 처리와 프로그램의 흐름을 제어하는 키워드밖에 들어있지 않습니다. 그렇기 때문에 표준 입출력에 관한 것은 외부에 의존합니다.
저번히 예제에 나온 printf라는 것도 키워드가 아님니다.
이것이 무엇인지는 오늘 배우게 됨니다.

(2) 심볼
심볼은 무언가를 상징하는 단어로 키워드와는 반대의 의미를 가지는 단어라고 할수 있습니다.
즉 이건 컴파일러가 특별한 의미로 인식하는 단어가 아닌 프로그램을 만드는 사람이 특별한 의미를 부여하는 단어 입니다.
키워드와는 다르게 프로그램을 만드는 사람이 특별한 기능을 수행하도록 만들게 되죠.
이 심볼에 해당하는 것은 오늘 배울 변수와 함수 이름등이 있습니다.
심볼은 한개 이상의 문자로 만들수 있으며 이때 사용할수 있는 문자는 알파벳과, 숫자, 언더 스코어('_')가 있습니다.
그런데 멘 처음 문자는 반드시 알파벳 또는 언더스코어가 와야 합니다.
예를 들자면..
symbol, _symbol, symbol1
이런것들은 심볼이 될수 있지만..
1symbol, 2symbol
이런건 에러가 나게 됨니다..

(3) 문장
문장은 프로그램을 구성하는 중요한 요소로 실행 단위가 된다고 할수 있습니다.
문장에는..
a=b+c;
printf("Example");
이런 것들이 있으며, 문장 이 끝나면 반드시 ';'를 써 주어야 합니다.
;이 문장의 끝을 알리는 표시 이죠.

(4) 블럭
블럭은 문장을 묶어 둔 것 입니다.
즉 한개 이상의 문장이 모여 있는 것을 말하죠.
블럭은 {로 시작해 }로 끝남니다.
예를들어..
{
a=b+c;
b=a+c;
}
이건 블럭이라 할수 있습니다.
그리고 블럭은 중첩될수도 있습니다.
{
a=b+c;
{
b=a+c;
}
}
이런 식으로 말입니다.

2. C 프로그램의 구조.

예제 소스를 하나 보며 공부하도록 하죠.
/* 파일 이름 : C2-1.C
프로그램 내용 : 계산에 대한 결과를 출력하는 프로그램 */
#include
int add(int,int); /* 두 수를 더하는 함수 */
void main()
{
int result; /* 변수 선언 */
result=add(3,5); /* add함수를 호출해 3과 5를 더한다. */
printf("Result:%d\n",result); /* result의 값을 출력한다. */
}
int add(int a, int b)
{
return(a+b); /* a와 b를 더해서 리턴 */
}
이 프로그램은 아주 간단하지만 처음 하시는 분은 좀 복잡해 보일 겁니다.
우선 저번 강좌 내용을 들춰 보면서 그때 나온 소스들과 이 소스를 비교해 보세요.
이 소스와 저번 강좌에 나왔던 여러 소스를 비교해 보면 공통점이 몇 가지 있을 것 입니다.
우선 프로그램 처음에 #include 라는 것이 꼭 있고 void main()이라는 것이 어느 소스에나 있을 겁니다.
이것들이 왜 공통적으로 들어 있는지 소스 분석을 통해 알아보죠.

(1) 선행처리기 지시어.

여기서 한 줄씩 살펴보기로 하죠.
우선 처음에는
#include
이런 문장이 있습니다.
이 문장처럼 #가 붙은 것을 선행처리기 지시어라고 합니다.
저번 강의때 들은적이 있으실 겁니다.
이 선행처리기 지시어는 메크로 기능, 파일 포함 기능, 선택적 컴파일 기능등 여러 기능을 수행합니다.
그중 여기 나온 #include라는 지시어는 지정된 파일을 프로그램 내에 포함시키라는 지시어 입니다.
그러니까 위와 같은 경우 stdio.h라는 파일을 프로그램 내에 포함시키라는 것이죠.
자세한 사용법을 살펴보면
#include <포함할 파일>
#include "포함할 파일"
이렇게 두가지 형식이 있습니다.
처음 방법은 지정된 디렉토리에서 파일을 찾아 포함시키는 것 입니다.
지정된 디렉토리는 흔히 개발 도구의 INCLUDE디렉토리를 가르키는 것으로 그 안에 들어 있는 파일은 개발 도구를 만든 곳에서 지원하는 것 들입니다.
두번째 방법은 현제 위치한 디렉토리에서 파일을 찾아 포함시키는 것 입니다.
예를들어 현제 디렉토리의 a.h라는 파일이 있는데, 그걸 포함시키고 싶다면.
#include "a.h"
이렇게 하면 됨니다.
대부분의 프로그램에서 stdio.h라는 파일을 포함시키는 이유는 차차 배우게 될 것입니다.
(2) 함수와 main함수
두번째 줄은 일단 넘어가기로 하고 다음을 보면
void main()
{
int result; /* 변수 선언 */
result=add(3,5); /* add함수를 호출해 3과 5를 더한다. */
printf("Result:%d\n",result); /* result의 값을 출력한다. */
}
이것이 있습니다.
이렇게 생긴 것들을 함수라고 하는데 함수란 어떤 내용을 처리하고 그 결과를 리턴하는 프로그램의 한 부분입니다.
반드시 하나의 블럭으로 되어 있어야 하죠.
그리고 그 안에는 그 함수가 처리할 내용이 들어가게 됨니다.
함수는 다음과 같은 구조로 만듬니다.
리턴형태 함수이름([인수, 인수, 인수...])
{
/* 프로그램 내용 */
.
.
}
여기서 리턴형태이란 처리하고 난 후의 리턴할 결과의 형태가 무엇인지를 쓰는 것 입니다. 즉 정수형태인지, 문자열인지 등등.. 결과를 리턴하지 않는 경우 void를 씀니다.
함수 이름은 그 함수를 상징하는 심볼 이죠.
인수는 그 함수가 어떤 내용을 처리할때 필요해서 전달받아야 할 데이터 입니다. 예를 들어 화면에 무언가를 출력하는 함수를 만든다고 합시다.
출력하기 위해선 출력할 내용을 전달받아야 하는데 그때 인수를 통해 전달받게 됨니다. 전달받을 데이터가 없으면 안써도 됨니다.
우선 지금 나온 함수는 main이라는 함수인데 이 함수는 어떤 프로그램이든지 존제하고 있었죠?
왜 그럴까요????????????????????
이유는 C언어 프로그램은 바로 main함수에서 시작하게 되기 때문이죠.
C프로그램의 실행되면 이 main함수를 시작으로 프로그램이 진행되고
main함수가 끝나면 프로그램도 끝나게 됨니다.
그러므로 반드시 만들어야할 함수 입니다.
main함수안에 나오는 것을 하나씩 분석해 보면.
int result; /* 변수 선언 */
처음에 이게 나오는데.. 이건 변수를 선언하는 것 입니다.
그냥 어떤 값을 저장하기 위해 기억장소를 마련하는 것이라 생각하시면 됨니다.
다음줄은
result=add(3,5); /* add함수를 호출해 3과 5를 더한다. */
이것인데..
이것은 바로 함수를 호출하는 것 입니다.
그리고 나서 그 결과를 result라는 기억장소에 보관하라는 뜻이죠.
그러니까 지정한 함수 내에 처리 내용을 실행시키고 그때 나온 결과를 result라는 변수에 보관하는 문장입니다.
함수 호출법은 다음과 같습니다.
[변수=]함수이름([인수,인수,인수..]);
여기서 변수는 함수의 내용이 처리된 후 리턴하는 결과를 넣을 기억장소를 말합니다. 결과를 리턴하지 않으면 쓰지 않아도 됨니다.
또한 리턴한 결과를 따로 저장할 필요가 없을때도 쓰지 않아도 됩니다.
그리고 함수이름은 호출할 함수를 상징하는 심볼, 인수는 함수가 하는 처리에 필요한 데이터입니다.
함수를 호출할 때는 그 함수가 만들어져 있어야 합니다.
그리고 함수가 호출하려는 곳보다 밑에 만들어 져 있으면 좋지 않죠. 이유는 위에서는 함수가 있는지를 모르거든요.
그런데 여기선 add라는 함수가 밑에 있죠?
이럴땐 함수를 위에 선언해 주면 좋습니다.
함수가 있다는 것을 알려주는 것이죠.
꼭 그래야 하는 건 아니지만, 요즘 컴파일러들은 경고를 주게 되죠.
그래서 add함수를 선언한 것이 main함수 위에 있는 것인
int add(int,int); /* 두 수를 더하는 함수 */
이거 입니다. 함수 선언은 간단한데..
리턴형 함수이름([인수, 인수, 인수...]);
이렇게 하면 됨니다. 이것들이 무슨 뜻 인지는 다 아시겠죠?
이렇게 함수를 선언한것을 C에서는 프로토타입을 선언한다고 합니다. 이렇게 프로토타입을 선언하면 에러가 방지되는 등의 좋은 점이 있으므로 프로토타입을 선언하는
습관을 기르는 것이 좋습니다.
이제 add를 호출했으니 add내의 내용을 살펴보죠
add함수를 보면
int add(int a, int b)
{
return(a+b); /* a와 b를 더해서 리턴 */
}
이렇게 되어 있습니다.
우선 리턴하는 결과는 정수입니다. int가 정수를 의미하거든요.
int와 같은 것에 대해서는 다음 강좌때 배움니다.
그리고 인수는 a, b두개인데, 아까
result=add(3,5);
이렇게 호출했으므로 a에는 3이, b에는 5가 각각 들어갑니다.
그리고 다음줄은
return(a+b); /* a와 b를 더해서 리턴 */
이것인데..
이건 함수의 처리를 끝내고 함수를 빠져 나오라는 것 입니다.
또한 함수를 빠져 나올때 a와 b를 더해서 결과로 리턴하라는 것이죠.
여기에 쓰인 return은 이렇게 함수를 빠져 나올때 쓰입니다.
사용법은
return [리턴값];
이때 리턴값이란 결과로 리턴을 해 줄 값을 말합니다.
예를들어 3을 리턴해 주려고 한다면.
return 3;
이렇게 써 주면 됨니다..
그리고 리턴값을 (와 )로 묶어주면 더 좋겠죠?
return(3);
이렇게..
특히 리턴값이 식으로 표현될때는 묶어주는 습과을 기르도록 하세요..
return(a+5);
이렇게 말이에요.
만약 함수가 아무 값도 리턴을 하지 않는다면, 리턴값은 생략해도 됨니다.
add함수가 3+5를 더한 값인 8을 결과로 리턴하겠네요?
그리고 리턴을 했으니 다시 main함수로 돌아와야 겠죠?
이때 아까
result=add(3,5);
이렇게 호출했으므로 result에는 8이 들어가겠군요.
그럼 다음줄을 볼까요.
printf("Result:%d\n",result); /* result의 값을 출력한다. */
이것 역시 함수를 호출하는 건데..
result값을 화면에 표시하는 기능을 하는 것 입니다.
그런데 좀 이상한게 있지 않나요??
printf라는 함수는 만들지도 않았는데 어떻게 호출했을까요??
그리고 선언 조차도 되어 있지 않죠?
이 함수는 바로 stdio.h라는 파일에 선언되어 있습니다.
stdio.h파일을 포함하는 이유가 바로 이것 때문이죠.
물론 선언을 하지 않아도 상관 없지만 말입니다.
그런데 이 함수를 선언했다 해도 실제 함수가 만들어져 있지 않죠?
이 함수는 C언어 개발 패키지를 만든 곳에서 지원하는 함수로 그곳에서 만들어 컴파일해서 목적 파일로 만든 후 기타 다른 함수들의 목적 파일과 같이 하나의 파일로 묶여 있습니다.
이렇게 목적 파일 한개 이상을 묵은 것을 라이브러리 라고 하고 확장자는 .LIB가 됨니다.
저번 강의때 들은적이 있죠? 라이브러리란 말을.. 그리고 저번 강의때 나온 런타임 라이브러리가
바로 printf함수가 들어있는 라이브러리로 이런 이유때문에 링크시에 런타임 라이브러리가 합쳐지는 것이죠.
런타임 라이브러리가 없으면 printf라는 함수를 쓰지 못하게 되거든요.
이렇게 해서 main함수가 끝났네요 그럼 프로그램이 종료되게 됨니다.
이제 프로그램의 결과를 보기로 하죠.
분석한게 맞았다면 결과가 8이 되겠죠?

C:\>C2-1.EXE
Result:8
C:\>
역시 맞군요..
(3) 다시한번 정리..
이제 간단히 C프로그램의 구조를 정리해보겠습니다.
C프로그램은 기본적으로 다음과 같은 구조로 되어 있습니다.
1. 선행처리기 지시어 부분.
2. 전역 데이터 및 함수 선언 부분.
3. 함수 부분.
처음으로 선행처리기 지시어 부분은
말 그대로 선행처리기 지시어들을 쓰는 부분입니다.
#include외에 여러가지 지시어들은 나중에 배우게 됨니다.
그리고 선행처리기 지시어는 반드시 #로 시작한다는 것을 기억하세요.
두번째 부분은 전역 변수 및 함수 선언 부분 인데 전역 데이터를 선언하거나 함수를 선언하는 곳 입니다.
전역 데이터란 모든 함수에서 사용할수 있는 데이터를 말하는 것으로 다음에 자세히 배움니다.
그리고 함수 선언은 무엇인지 배우셨고... 세번째 부분은 함수 부분 인데 실제적인 프로그램을 기술하는 곳으로서 가장 중요하다고 볼수 있죠.
특히 main함수는 반드시 만들어야 한다는 것을 잊지 마시기 바람니다.
마지막으로 두번째부분은 다른 파일에 따로 기술하여 #include지시어를 통해 포함시키기도 하는데 이때 그 다른 파일을 헤더(앞부분이기 때문)파일이라고 하고 확장자는 .H입니다
그리고 stdio.h도 헤더파일 입니다.
이번 강좌에서는 C 프로그램의 구조를 비교적 자세히 알아보았습니다.
다음 강좌에서는 데이터에 대한 공부를 하겠습니다. 

1. C언어 소개



제가 C언어 강좌를 시작하려고 합니다. 제가 아는 모든 내용을 잘 정리해 쓴 것입니다. 부족한 점 있더라고 잘 봐주세요.

C언어란 것은 아주 강력한 기능을 가진 프로그래밍 언어 입니다.
C언어가 Unix운영체제 하에서 시스템 프로그래밍을 하기 위해 개발된 언어라는건 알고 있지만 정확히 누가 만들었는지는 저두 잘 모릅니다.
사실 그건 중요한게 아니죠.
C언어는 구조화 프로그래밍을 지향하는 언어이고 정말로 가장 쓸모있는 언어라고 할수 있습니다. 이유는 C언어에서는 못하는게 없기 때문이죠.
좀 과장된 표현 같기도 하지만 다른 언어들과 비교해 볼때 못하는거란 없습니다. 그리고 C언어로 만든 프로그램의 속도는 어셈블리어 만큼이나 빠른 속도를 내기 때문에 빠른 속도를 요구하는 프로그램에도 적합하죠.
단 게임과 같은 곳에서는 C언어의 속도도 조차도 느리기 때문에 어셈블리가 요구되는 곳이 있지만, 요즘 C언어 컴파일러들은 인라인 어셈블러라는 것을 지원해서 C소스 내에 어셈블리 코드를
추가할수 있습니다. 이런 점으로 볼때 C로는 못하는게 없다고 봐도 되겠죠?
그래도 실감이 나지 않으시면 C언어로 만들어진 대표적인 프로그램을 예로 들어 볼까요? 그런데 그럴려면 한가지 문제가 있네요.
이 문제가 뭐냐 하면.. C언어로 만들어진 유명한 프로그램이 너무나도많다는 것이죠. 그래도 몇가지 예를 들어 보죠.
우선 OS에서는 Unix의 커널의 일부분을 제외한 모든 부분이 C로 만들어 졌습니다.
정말 굉장하죠..?
그리고 Windows 95도 커널의 일부분과 *.VxD만 빼면 모두 C로 만들어졌습니다. 그것두 우리가 잘 알고 있는 Visual C++의 버전 2.1로 만들어졌죠.
또하나 굉장한 사실이 있는데 Windows NT는 커널 부분까지 C로 만들어졌다는 것이죠.
C언어로 만들어진 프로그램에는 게임도 많은데, 데부분의 게임은 C언어로 만들어졌다고 보면 됨니다.
게임을 시작할 때
DOS/4GW Protected Mode Run-time Version 1.97
Copyright (c) Rational Systems Inc. ............
이런 것을 많이 보셨을 겁니다. 유명한 게임을 시작할땐 다 이게 나오는데, 이게 나오는건 C언어도 만들어진 것 입니다. Watcom C++라는 개발 툴로 만들어진 것이죠.
또 한가지 놀라운 사실이 있는데, C언어 컴파일러도 C언어로 만든다는 것이죠.
이정도면 C언어로 못하는게 없다는 말이 이해가 되시겠죠?
그럼 이제 그 C언어의 세계로 들어가 보도록 하죠.

2. C언어에는 어떤 종류가..

'C언어에는 어떤 종류가..'라는 제목을 보고 글이 자꾸 읽고 싶어 지신다면 그 분은 분명 C언어 초보자 입니다. 하지만 이 제목을 보고선 무언가 이상하다고 느끼시면 진정한 전문가라고 할수 있죠.
이유가 궁금하시죠? 이유는 C언어에는 종류가 없기 때문이죠.
종류가 없는데 제목이 저러니 당연히 이상할수 밖에요.
C를 처음 하시는 분들이 많이 질문하시는 것들 중 하나가 'C와 Visual C의 차이점이 무엇인가요?' 입니다.
제가 이 질문을 받았다면 이렇게 답해 드리고 싶군요.
'C는 언어이고 Visual C는 언어가 아님니다.' 라구요.
여기서 Visual C라는 건 Microsoft라는 회사에서 만든 C언어로 프로그래밍 할때 필요한 도구를 말합니다.
즉 언어가 아니라는 것이죠.
단지 C언어로 프로그래밍을 할때 필요한 도구에 지나지 않습니다.
언어는 바로 C이죠.
그러므로 Visual C와 Borland C등은 문법에선 차이가 있을수 없습니다.
정리하면 C는 언어이고, Visual C, Borland C등은 언어가 아니라 C언어를 사용해 프로그램을 제작하기 위한 도구이며, 모두 C언어 프로그램을 제작하기 위한 도구 이므로 문법이 차이는 있을수 없다는 것을 꼭 기억하시기 바랍니다.
그리고 여기서 한가지 말씀드릴것이 있는데, 위에 Visual C라고 썼지만 실제는 이게 아니고 Visual C++입니다.
그럼 또 한가지 의문이 생기실건데 Visual C++에서 C++가 아닌 C언어 프로그램을 작성할수 있는지 말입니다.
이 의문의 답은 Yes!입니다.
C++라는 언어는 C언어를 객체 지향 프로그래밍이란 것을 할수 있도록 확장 시킨 언어 이죠. 그래서 C++언어는 C언어를 포함한다고 할수 있죠.
그러므로 Visual C++에서 아무리 C++라고 쓰여져 있어도 C프로그래밍은 가능합니다.
3. C언어는 어떻게..
이제 C언어 프로그램이 어떻게 실행되어 지는 가를 알아봅시다.
C언어로 프로그램을 만들면 실행파일(.EXE)을 만들 수가 있습니다.
실행파일이 만들어지데는 다음과 같은 과정을 거칩니다.

                    (텍스트 에디터)                      (선행처리기)
(1)소스 코드 -------------> (2)소스 파일 ------------> (3)선행처리기 지시어가
                                                                                                번역된 소스 파일


          (컴파일러,라이브러리)                             (링커)
        -------------------->(4)목적 파일 -----------> (5)실행파일


(1) 소스 코드 (Source)
프로그램의 내용 자체를 소스 코드라고 합니다. 

(2) 소스 파일 (Source file)
소스 코드를 택스트 파일에 기술하여 만들어진 파일을 소스 파일이라고 합니다. C언어의 소스 파일은 확장자가 .C입니다.
C언어 프로그램 만드는 가장 첫번째 과정이라고 할 수 있죠. 

(3) 선행처리기 지시어가 번역된 소스 파일
C언어 프로그램 내에는 여러가지 지시어 들이 있는데 이건 C언어 문법과는 별게이고 번역도 컴파일러가 하지 않습니다.
이걸 번역하는 프로그램을 선행처리기라고 합니다. 

(4) 목적 파일 (Object file)
지시어가 번역된 소스 파일은 다음으로 컴파일러라는 프로그램에 의해 기계어로 번역 됨니다. 이 번역된 파일을 목적 파일이라고 하고, 확장자는 .OBJ가 됨니다. 그러데 여기서 이상한 점이 있죠?
기계어로 번역하면 실행할수 있을 건데 왜???????? 실행파일을
만들지 않고 목적파일이라는 만들까요?
하지만 기계어로 번역되었다고 해서 실행할수는 없습니다.
실행파일이 되기 위해선 런타임 라이브러리 라는 것이 목적 파일과 합쳐져야 하기 때문이죠. 이 런타임 라이브러리가 무엇인지는 나중에 설멸하기로 하고 그냥 런타임 라이브러리라는 것이 합쳐져야 한다는 것만 알아두세요. 

(5) 실행 파일 (Executable file)
목적파일은 위에서 말한 런타임 라이브러리와 합쳐져서 실행파일이 되는데, 이때 합쳐주는 프로그램을 링커라고 합니다.
링커에 의해 목적 파일은 실행파일이 되죠.
그럼 실행할수가 있게 됨니다. 

4. C 프로그램의 기본적인 구조.

이정도 알았으면 이제 C언어 프로그램의 문법적인 구조를 살펴보기로 합시다.
이제부터 정말 C의 문법에 대한 공부를 들어갈탠데, 이번에 나올 C 프로그램은 기본적인 구조만 이해하시면 된검니다.
세부적인 부분은 모르셔도 됨니다.
기본적인 구조를 알고 계셔야 다음 강좌의 이해가 쉽기 때문이죠.
 
(1) 자유로운 형식
C언어는 다른 언어들과는 달리 형식이 메우 자유롭습니다.
우선 예제 소스 하나를 보며 공부해보도록 하죠. 
/* 파일 이름 : C1-1.C
프로그램 내용 : 화면에 메시지를 출력하는 프로그램. */
#include
void main()
{
printf("This is a first program.");
} 
이 소스는 아주 간단한 소스 입니다.
하지만 C를 처음 대하시는 분 이라면 아주 생소하게 느껴질 것 입니다.
이 소스 내용은 아직은 이해하지 못하셔도 되니까 검먹지 마시고 잘 봐주세요.
하여튼 그건 그렇고
아까 그 소스(C1-1.C)와 다음에 나오는 소스를 비교해 보세요. 
/* 파일 이름 : C1-2.C
프로그램 내용 : 화면에 메시지를 출력하는 프로그램. */
#include
void main(){printf("This is a first program.");} 
이 소스들을 비교해 보세요.
주시해서 봐야 할 곳은 void...); }부분 입니다.
두 소스중 어떤 것이 보기가 쉽죠???
당연히 첫번째 소스가 더 읽기 쉬울 것 입니다.
하지만 이 두 소스는 완전히 똑같은 기능을 수행합니다.
결과를 봐볼까요???
두 개를 컴파일해서 C1-1.EXE, C1-2.EXE를 만들고 실행하면.. 
C:\>C1-1.EXE
This is a first program.
C:\>C1-2.EXE
This is a first program.
C:\> 
똑같은 소스 이지만, 두번째 소스는 첫번째 소스를 한줄에 다 써 버린 것 입니다.
하지만 컴파일러는 똑같은 내용으로 인식하게 되죠.
여기서 말하고자 하는 것은 C언어 프로그램은 자유로운 형식을 같는다는 것 입니다.
즉 여러줄에 써야 할 것을 한줄에 써 버려도 상관 없다는 것이죠.
또한 이 말은 한줄에 써야 할 것을 여러줄에 쓸 수도 있다는 말 입니다.
더 정확히 말하자면 C언어 에서는 공백을 인식하지 않습니다.
즉 공백이 많이 있어도 그건 없는거나 마찬가지 이죠.
그러므로 첫번째 소스도 실제로 컴파일러에서는 두번째 소스처럼 인식하게 되는 것 입니다.
하지만 공백 없이 한 줄에 다 써 버리면 읽기가 힘들어 지므로, 되도록 보기 쉽게 공백을 두고 쓰는 것이 좋습니다. 

(2) 대소문자 구별

C언어는 대문자와 소문자를 구별한다는 것을 기억해 두시기 바랍니다.
예를들어 Basic에서 화면에 메시지를 출력하는 명령어인 PRINT는 print라고 써도 상관 없고 Print, prinT, pRint등으로 써도 모두 같은 것으로 인식합니다.
아지만 C에선 그렇지 않습니다.
베이직의 PRINT의 기능을 하는 것으로 아까 예제 소스에서 나온 것 인데.. C에서는 printf라는 것이 있습니다.
그런데 이걸 Printf, pRintf, PRINTF등등.. 이렇게 써서는 절데 안됨니다.
모두 다른 것으로 인식하기 때문에 반드시 printf로 써 주어야 하죠.
보통 C에서는 거의 다 소문자로 되어 있어요.
그리고 C언어가 지원하는 기본 어휘 그러니까.. 베이직에서는 PRINT, INPUT, DIM등등의 명령어들과 같은 역할을 하는 기본적 어휘를 키워드(예약어)라고 하는데, 이것들도 모두 소문자로 되어 있죠. 

(3) 주석 (설명문)

주석문은 프로그램과는 아무 상관이 없어 없는것과 마찬가지 이지만, 프로그램의 내용을 설명하기위해 쓰는 글 입니다.
C에서 주석문을 쓰는 것은 간단합니다.
설명하는 글 앞에는 /*를 붙이고 뒤에는 */를 붙이면 되는 것 입니다.
예를들어.. 
/* 주석문 입니다 */ 
이렇게 하면 주석문이 됨니다.
즉 없는 거나 마찬가지인 글이 되는 것이죠.
예제 소스를 하나 들어 보죠. 
/* 파일 이름 : C1-3.C
프로그램 내용 : 주석문을 설명하기 위한 프로그램. */
void main()
{
int a, b, c; /* 정수 변수 a, b, c를 선언 */ 
a=10; /* a에 10을 넣는다. */
b=20; /* b에 20을 넣는다. */
c=a+b; /* c에 a와 b를 더하여 넣는다. */
} 
여기서 /* */로 묵인 것은 모두 주석문 입니다.
즉 /* */로 묵인 것은 없어도 상관 없습니다.
그리고 주석문은 여러줄이 되어도 상관 없습니다. 
/* 주석문 입니다..
이것두 주석문 입니다.. */ 
이렇게 써도 상관 없다는 것 입니다.
C에서는 한줄에 쓸 것을 여러줄에 써두 된 다고 배웠는데, 위와 같이 주석문을 쓴 것두 
/* 주석문 입니다.. 이것두 주석문 입니다.. */ 
이렇게 써야 할 것을 위와 같이 쓴 것 뿐이라고 생각하시면 이해가 되실 것 입니다.
주석문을 쓰는 이유는 프로그램에 대한 설명을 써 둠으로써 읽기 쉽게 하고 오류를 찾아네거나 수정하는 작업을 쉽게 하기 위해서 입니다.
물론 간단한 프로그램의 경우 특별히 주석 없이도 충분히 읽을수가 있지만, 정말로 복잡한 프로그램에선 주석문이 큰 도움을 줄수 있죠.
주석문을 쓸 때는 공백을 최대한 이용하는 것이 좋습니다.
공백을 잘 이용하여 최대한 보기 쉽게 해야 하죠.
주석문이 필요한 이유가 프로그램을 읽기 쉽게 해서 오류를 찾거나 수정을 하는 일이 쉬워지게 하기 위해서 인데, 주석문을 보기 어렵게 쓰면 않되겠죠?
예를 들어 봅시다. 위에 나왔던 소스와 다음 소스를 비교해 보세요. 
/* 파일 이름 : C1-4.C
프로그램 내용 : 주석문을 설명하기 위한 프로그램. */
void main()
{
int a, b, c; /* 정수 변수
a, b, c를 선언 */
a=10; /* a에
10을 넣는다. */
b=20; /* b에 20을 넣는다. */
c=a+b; /* c에 a와 b를
더하여 넣는다. */ 
C1-4.C는 주석때문에 보기가 더 힘들어 졌죠?
주석문을 이렇게 써서는 절데로 않됨니다.
이것으로 이번 강좌는 마치도록 하겠습니다.
이번 강좌에는 별 이상한 예기들만 많이 한것 같군요.
다음 강좌부터는 본격적인 C프로그래밍에 들어가도록 하죠. 

2016년 4월 26일 화요일

윈도우 7 OEM DVD 만들기 - 중수편

1. Install.wim 파일 마운트
ImageX, GImageX 등을 이용해도 되고 윈도우 7 사용자라면 dism을 이용해도 됩니다. 저는 dism으로 설명드리겠습니다.

a. Install.wim 파일을 하드에 복사한다. (E 드라이브에 복사했다고 가정)
b. 마운트할 폴더를 하나 만든다. (E 드라이브에 mount 폴더를 생성했다고 가정)
c. 편집할 이미지를 마운트한다. (32비트 홈프리미엄 버전이라 가정)
예제) dism /mount-wim /wimfile:e:\install.wim /index:3 /mountdir:e:\mount

2. OEM 라이선스 복사
OEM 라이선스 파일을 (확장자 xrm-ms) 아래 경로에 복사한다. 파일 이름은 상관이 없다. 그리고 여러개의 파일을 넣어도 된다. 참고로 System32 폴더 아래에는 원래 OEM 폴더가 없다. 생성해주면 된다.
예제) e:\mount\Windows\System32\OEM\sec.xrm-ms

3. 시디키 입력
에디션에 맞는 OEM SLP 키를 입력하면 된다.
예제) dism /image:e:\mount /set-productkey:xxxxx-xxxxx-xxxxx-xxxxx-xxxxx

4. 적용 및 언마운트
변경된 내용을 Install.wim 파일에 적용하면서 마운트를 해제한다.
예제) dism /unmount-wim /mountdir:e:\mount /commit

5. ISO 제작
변경된 Install.wim 파일을 원본 ISO 파일에 교체한다.

boot.wim 파일 편집으로 윈도우 7 자동설치 만들기

2009년에 재당 정사님이 이 글의 내용과 비슷한 구성을 하려고 댓글로 질문을 하셨고, 당시에 제가 답변을 드렸는데, 오늘 회사에서 심심해서(?) 한번 만들어 봤습니다. 글을 시작하기 전에 미리 말씀드립니다만, 이 글에서 다루는 내용을 실제로 활용하실 분들은 거의 없으리라 생각합니다. 그럼에도 불구하고 이런거 재미있어 하는 분들은 나름대로 응용해서 활용하시리라 생각하기 때문에 간단히 컨셉만 소개해드립니다.

일단 오늘 제가 회사에서 이 작업을 했던 이유는

1. 동일한 스펙의 1U짜리 서버 8대에 윈도우 서버 2008 R2를 설치해야 한다.
2. 그런데 설치할 디스크를 선택하고, 파티션을 나누는 일이 너무 귀찮다.
3. 물론 설치 초반에 Next 버튼을 몇번 누르는 일 조차도 귀찮다.
4. 게다가 무인설치 응답파일을 만드는 일은 더더욱 귀찮다.

그래서 제가 구상한 방식은 다음과 같습니다.

1. boot.wim 파일에 들어있는 setup.exe 파일을 가짜 파일로 교체한다.
  a. 이 가짜 setup.exe 파일은 단순히 sources 폴더에 들어있는 start.cmd 파일만 호출한다.
  b. 이 가짜 setup.exe 파일은 Quick Batch File Compiler로 만들 수 있다.
2. sources 폴더에 넣어줄 start.cmd 파일은 아래와 같은 역할을 한다.
  a. diskpart로 0번 디스크 초기화 및 파티셔닝, 활성화 등
  b. imagex로 install.wim 파일 하드에 풀어주기
  c. bcdboot으로 부팅파일 생성해주기

물론 가짜 setup.exe 파일이 바로 start.cmd 파일의 역할을 수행하도록 만들어도 되지만, 그렇게 하면 유지보수가 매우 불편합니다. 매번 소스를 수정하고 싶을 때 마다 setup.exe 파일을 새로 컴파일하고 boot.wim 파일 안에 넣어줘야 하기 때문입니다. 따라서 이렇게 setup.exe 파일은 start.cmd 파일을 호출만 하도록 만드는게 좋은 방법이라 생각합니다. start.cmd 파일을 수정하는 일은 매우 쉬우니까요.

어차피 이 작업은 초보 분들이 하기에 적합하지 않다고 생각하기 때문에, 그림 없이 텍스트로만 설명드리겠습니다.

1. 가짜 setup.exe 파일 만들기

먼저 가짜 setup.exe 파일을 만들어봅시다. 위에서 말씀드렸듯이 이놈의 역할은 단순히 sources 폴더에 들어있는 start.cmd 파일을 실행만 시키는 역할을 합니다. 따라서 저는 아래와 같이 짜겠습니다.

예제) setup.cmd
@echo off
for %%a in (C D E F G H I J K L M N O P Q R S T U V W X Y Z) do (
 if exist %%a:\sources\start.cmd %%a:\sources\start.cmd
)

그리고 이놈을 Quick Batch File Compiler를 사용해 exe로 컴파일 하겠습니다.

Quick Batch File Compiler 홈페이지
http://www.abyssmedia.com/quickbfc/

사용법은 따로 설명드리지 않겠습니다. 그냥 트라이얼 버전으로 바로 컴파일 하셔도 됩니다. 귀찮으실 분들을 위해 제가 위 예제를 트라이얼 버전으로 컴파일한 파일 올려드립니다. 바이러스로 오진할 수도 있는데, QBFC로 컴파일하면 원래 오진을 많이 합니다. 저를 못 믿으시는 분들은 직접 컴파일해서 사용하시기 바랍니다.


2. boot.wim 파일 편집

이제 boot.wim 파일을 마운트해서 가짜 setup.exe 파일을 넣어줄 차례입니다. 여기서 사용하실 boot.wim 파일은 반드시 32비트 버전이어야 합니다. 왜냐하면 QBFC로 컴파일한 exe 파일이 32비트 버전이기 때문입니다. 저는 윈도우 7 SP1 32비트 원본에서 boot.wim 파일을 가져와 D 드라이브 루트에 복사해놓고 작업을 진행하겠습니다.

파일 편집 자체는 dism 명령어를 사용해도 되고, ImageX나 GImageX를 사용해도 됩니다만, 저는 어차피 나중에 ImageX를 ISO 파일 안에 넣을 생각이기 때문에, 여기서도 ImageX로 진행하겠습니다.


지금부터 하는 모든 커맨드 작업은 관리자 권한으로 명령 프롬프트를 띄워서 실행해주세요.

a. boot.wim 파일을 마운트할 폴더를 먼저 생성해둡니다.
예제) md d:\mount

b. ImageX로 boot.wim 파일의 2번 이미지를 마운트합니다. 
예제) imagex /mountrw d:\boot.wim 2 d:\mount

c. 마운트된 폴더에서 setup.exe 파일을 삭제합니다.

d. 가짜 setup.exe 파일을 마운트된 폴더에 복사합니다.

e. ImageX로 boot.wim 파일을 언마운트/커밋 합니다. 이때 마운트된 폴더가 탐색기에 열려 있으면 안 됩니다.
예제) imagex /unmount d:\mount /commit

f. 깔끔하게 export 한번 해주겠습니다.
예제) imagex /export d:\boot.wim * d:\new.wim

g. boot.wim 파일은 삭제하고 new.wim 파일의 이름을 boot.wim 으로 변경합니다.


3. start.cmd 파일 만들기

여기서부터는 여러분의 영역입니다. 자유롭게 자신이 원하는 방식으로 배치파일을 작성하시면 되겠습니다. 저는 서두에 말씀드린 작업을 예제로 보여드리겠습니다.

예제) start.cmd
@echo off
cd /d %~dp0
diskpart /s diskpart.txt
imagex /apply install.wim 3 c:
bcdboot c:\windows /s c: /l ko-kr

예제) diskpart.txt
select disk 0
clean
create partition primary size=102400
format quick
active
assign letter=c
create partition primary
format quick
assign
exit

위 2개의 파일이 어떤 역할을 하는지 대충 눈에 보이시나요?

디스크 0번을 선택해서 초기화 시킨 다음
첫번째 파티션을 100GB로 만들고
포맷을 한 다음
활성화 속성을 걸어주고
드라이브 문자를 C로 할당합니다.

두번째 파티션을 나머지 공간 전체에 할당하고
포맷을 한 다음
드라이브 문자를 할당합니다.

ImageX로 Install.wim 파일의 3번 이미지를 C 드라이브에 풀어줍니다.

bcdboot으로 C 드라이브에 부팅파일을 생성해줍니다.

위 예제는 어디까지나 제가 1U짜리 서버 8대에 윈도우 서버 2008 R2 SP1 Enterprise 버전을 동일한 방식으로 설치하기 위해 만들어둔 것 뿐입니다. 여러분은 각자 상황에 맞게 스크립트를 변경하셔야 합니다. 위 스크립트를 그대로 사용하셨다가는 디스크 0번의 파티션들이 완전히 날아가고 새로 생성됩니다. 따라서 신중하게 작업해주기시 바랍니다.


4. 마무리

이제 다 됐습니다. 설치할 윈도우 7이나 2008 R2 원본 이미지의 sources 폴더에 위 파일들을 넣어주시면 됩니다. 그러니까 저같은 경우 파일 4개를 넣으면 되는 상황입니다.

boot.wim
start.cmd
diskpart.txt
imagex.exe

용량을 줄이기 위해 저는 불필요한 파일들을 전부 삭제했습니다.


이걸로 부팅하면 어떻게 되는지 동영상으로 보여드리겠습니다. 키보드를 한번도 입력하지 않아도 윈도우 설치 마지막 화면까지 논스톱으로 진행이 됩니다.



물론 여기서 더 귀차니즘을 느낀다면 Install.wim 파일에 시디키도 미리 입력시켜놓고, 무인설치 응답파일로 마지막 OOBE 단계까지 자동화 시켜버릴 수도 있습니다. 또한 순정 Install.wim 파일을 사용하지 않고 만능 고스트처럼 여러가지 프로그램을 셋팅해둔 상태로 Sysprep 일반화 봉인된 Install.wim 파일을 활용할 수도 있겠죠.

오랜만에 geek 스러운 글을 올린 것 같은데, 다시 말씀드리지만 저는 동일한 스펙의 여러대의 서버에 설치 작업을 반복해야 하기 때문에 귀찮아서 이렇게 만든 것입니다. 위 예제를 그대로 사용하시면 첫번째 디스크의 파티션이 전부 날아가고 재구성되니 절대로 그대로 따라하지는 마시고, 각자 환경에 맞게 스크립트를 잘 짜서 사용하시기 바랍니다. 이상입니다.