개발자/C#

C언어 관련 주요 질문과 답변

지구빵집 2011. 1. 12. 16:58
반응형

지난거지만~~~ 참고로... 출처 : http://www.dal.kr/chair/c/c2301.html

[부록]


23.C언어 관련 주요 질문과 답변


부록으로 실은 이유

부록으로 실은 주요 질문과 답변은 그 동안 제가 전자우편이나 홈페이지를 통해 받은 많은 질문과 답변 중에서 가장 빈번하게 묻는 내용을 중심으로 정리한 것입니다. 질문 내용을 보면 알겠지만 책에 설명한 내용을 물어본 경우가 꽤 많습니다. 이런 경우는 제 책의 독자가 질문한 것이 아니라 제 홈페이지를 방문했다가 물어본 경우에 속합니다. 책에 설명한 내용이라 중복되는 부분도 있지만 가장 많이 질문하는 경우라서 그대로 수록했습니다. 책 본문과 중복되는 내용은 복습이라 생각하고 봐주시면 고맙겠습니다.

지면 관계로 책에 모든 질문과 답을 다 수록하지 못했습니다. 책에 수록한 내용은 가장 보편적이고 이 책의 수준에 어울리는 것들만 뽑아서 수록한 것입니다. 좀더 많은 질문과 답변을 보고 싶다면 제 홈페이지로 접속하시면 됩니다.

홈페이지에 접속하면 볼 수 있는 질문을 구태여 책에 수록한 이유는 홈페이지 접속이 어려운 독자를 위해서입니다. 아직도 여러 가지 이유로 인터넷에 접속하지 못하는 분들이 많습니다.
예를 들어 군대에서 남는 시간을 이용해 C언어를 배우는 사람은 인터넷에 접속할 수 있는 환경이 못됩니다. 경제 형편 문제로 고속통신망을 설치하지 못하는 사람도 있고 제 책을 도서관에서 빌려서 보는 사람도 있습니다. 이런 다양한 환경의 독자를 위해 부록으로 주요 질문과 답변을 수록했다는 점을 이해하여 주시기 바랍니다.

인터넷을 사용할 수 있는 독자라면 이 책을 읽다가 궁금한 점이 있을 경우, 언제든지 제 홈페이지의 게시판과 전자우편으로 문의하시기 바랍니다.


질문 목록(유형별)

   23.1.컴파일러 사용에 대한 질문
      23.1.1.한글윈도에서 테두리선이 '컴컴컴'으로 깨져보이는 현상과 해결 방법
      23.1.2. 볼랜드사의 C언어 프로그램 계보는?
      23.1.3. 터보C는 공개용 프로그램인가요?
      23.1.4. 볼랜드C++은 공개용 프로그램인가요?
      23.1.5. 터보C하고 터보C++이 공개라는데 어디서 구할 수 있나요? 960
      23.1.6. 볼랜드사의 기타 공개 프로그램과 다운로드 주소는?
      23.1.7. 리눅스용 컴파일러와 다운로드 주소
      23.1.8. 볼랜드사의 컴파일러를 학생판으로 싸게 구입할 수 있나요?
      23.1.9. 터보C 설치 때 다음 디스켓 넣으라는 안내문에서 막힙니다.
      23.1.10. 터보C에서 한 번 설정한 환경을 그대로 유지하려면?
      23.1.11. 컴파일러가 다르면 C 문법도 다른가요?
      23.1.12. 터보C나 볼랜드C++ 로 만든 소스 파일을 비주얼C++에서 컴파일할 수 있나요?
      23.1.13. 도스용 볼랜드C++로 윈도용 프로그램을 만들 수 있나요? 964
      23.1.14. 자신이 사용하는 컴파일러 프로그램에 예제 파일이 없는 경우
      23.1.15. 리눅스용gcc에서 그래픽을 처리하려면?
      23.1.16. 주석 달 때 한글 글꼴이 옆으로 누워서 보이는 이유와 해결 방법
      23.1.17. 여러 개의 예제 창을 닫는 방법과 다음 실행 때 예제가 안 불러오게 하는 방법은?
      23.1.18. 도스창에서 실행한 프로그램이 종료 후 자동으로 도스창 안닫게 하려면?
      23.1.19. 선언한 배열 첨자 이상을 접근할 때 컴퓨터가 먹통이 안되게 하는 컴파일 옵션이 있나요?
      23.1.20. 스크롤 되어 넘어간 화면은 어떻게 보나요?
   23.2. 문법 관련 질문
      23.2.1. word, bool, cord 등의 자료형은 어디에 사용합니까?
      23.2.2. 실수형 변수가 정수형으로 출력되지 않는 이유는?
      23.2.3.제곱 구하기 함수에서 큰 수를 제곱했을 때 엉뚱한 결과로 나오는 이유
      23.2.4.123.45가 123.459997로 출력되는 이유
      23.2.5.float형보다 double형을 많이 사용하는 이유는?
      23.2.6.long형(정수) * 실수 = long형(정수형). 근데 답이 부정확합니다.
      23.2.7.왜 C에는 문자열형이라는 자료형이 없는 거죠?
      23.2.8.변수 대입을 분수로 하면 안되나요? n=1/3으로 하면 3.33이 아니라 0이 나오네요.
      23.2.9.실수형은 논리값을 가질 수 없나요?
      23.2.10. main() 함수를 미리 선언할 수 없는 이유
      23.2.11.0을 돌려줄 거라면 return 0; 대신 void kim(void)를 써도 되는 것 아닌가요?
      23.2.12.int main(void)과 void main(void) 중 아무 거나 써도 상관 없나요?
      23.2.13. main() 함수의 되돌림값은 어디에 돌려주나요?
      23.2.14. printf()함수에서 왼쪽 정렬과 오른쪽 정렬의 개념과 기준 986
      23.2.15.printf()문의 정렬 방법과 결과의 불일치 문제
      23.2.16. <>와 "" 기호의 차이
      23.2.17.include 와 scanf() 생략할 경우의 현상
      23.2.18. for 문에서 명령 실행 순서
      23.2.19.문자열을 저장하는 방법에는 어떤 것이 있는지 궁금합니다 997
      23.2.20.배열에 저장된 값을 역순(거꾸로)으로 출력하는 방법
      23.2.21.입력받은 변수의 숫자로 배열의 크기를 선언하는 것이 가능한가요?
      23.2.22.크기를 모르는 배열을 지정하는 방법과 배열 수만큼 %d를 사용하는 방법
      23.2.23. ## 기호의 의미
      23.2.24.표준입출력 장치란?
   23.3.오류 처리 방법
      23.3.1.[Statement missing ;]
      23.3.2.Undefined symbol '1SYMBOL' in module '2MODULE' 1003
      23.3.3.'xxxxx' : undeclared identifier
      23.3.4.[Function 'printf' should have a prototype]
      23.3.5.[Unable to open include file 'STDIO.H']와 [Function 'printf' should have a prototype]
      23.3.6.[Unable to open include file 'STDIO.H']와 [Unable to creat output file C:\BC31\WORK\TEST.obj]의 관계
      23.3.7.Unable to create output file 'hello.obj'
      23.3.8.볼랜드C++에서 textattr 함수를 인식 못합니다.
      23.3.9.헤더 파일을 적어주었는데도 함수가 선언되지 않았다고 나옵니다.
      23.3.10.[No module definition file specified : Using defaults]
      23.3.11.[Square Root of Negative Number]
   23.4.C언어 공부에 대한 질문
      23.4.1. C를 먼저 배워야 C++을 배울 수 있나요?
      23.4.2. C++을 배우려고 하는데 C언어를 먼저 배우는 것이 더 효과적인가요?
      23.4.3. C언어(터보C)로 C++ 프로그램을 만들 수 있나요?
      23.4.4. 윈도2000이라 도스가 없는데 도스가 없어도 C나 C++을 배울 수 있나요?
      23.4.5. 비주얼C++보다 IDE 기반의 도스용 C++을 배우는 것이 나은 이유
      23.4.6.프로그램 실력이 안 느는 이유는 무엇일까요?
      23.4.7.C언어하고 게임 프로그램 하고 관련이 있나요?
      23.4.8.컴퓨터 학과 아닌 사람이라면 C언어를 배울 필요 없나요? 1026
      23.4.9.수학을 알아야 C언어를 배울 수 있나요?
      23.4.10.C언어를 알아야 해킹을 할 수 있나요?
      23.4.11. obj, exe 파일을 추적해 소스 파일을 알아낼 수 있나요?1027
      23.4.12. 노트북으로도 프로그램 작업이 가능한가요?
      23.4.13. 한글 코드 구현 관련 서적
      23.4.14. 한글 라이브러리 파일 구하기

23.1.컴파일러 사용에 대한 질문


23.1.1.한글윈도에서 테두리선이 '컴컴컴'으로 깨져보이는 현상과 해결 방법


[질문] 한글윈도에서 도스창으로 터보C나 볼랜드C++을 실행시키면 테두리선 부분이 '컴컴컴'으로 글자가 깨지는 현상이 나타나 글자를 알아볼 수 없습니다.

[답변]
(1) 한글윈도나 한글 도스에서 테두리선문자가 깨지는 이유


한글윈도나 한글도스를 사용하는 분들의 경우 도스 상에서 프로그램을 실행시키면 테두리선 부분이 이상한 글씨로 깨져나오는 현상이 있습니다. 그 까닭은 윈도나 도스가 완성형한글을 사용하기 때문입니다.
완성형한글을 사용하기 때문에 영어 상태에서는 테두리선문자(네모 상자나 테두리선을 그릴 때 사용하는 문자들을 말함)로 보이는데 한글 상태에서는 테두리선 깨짐 현상이 나타납니다.



**사진: TC를 실행시켰을 때 나오는 테두리선 깨짐 현상의 보기



**사진: BC를 실행시켰을 때 나오는 테두리선 깨짐 현상의 보기

(2) 테두리선문자 깨짐 현상을 없애는 방법


이처럼 영문 프로그램을 구동시켰을 때 테두리선문자가 깨져나오는 현상을 해결하는 방법은 다음과 같습니다.

1. 영문도스로 부팅하는 방법
2. 한글도스로 부팅한 후 한글구동 프로그램을 메모리에서 제거하는 방법
3. 한글도스로 부팅 후에 한글구동 프로그램의 활동을 잠시 꺼놓는 방법

한글윈도를 사용하면서 도스창을 이용하는 경우에는 다음과 같은 해결방법이 있습니다.

4. 영문도스창으로 도스창을 실행시키는 방법
5. 한글도스창으로 실행한 후에 한글구동 프로그램을 메모리에서 제거하는 방법
6. 한글도스창으로 실행한 후에 한글구동 프로그램의 활동을 잠시 꺼놓는 방법

이 중 영문도스로 부팅하는 1번 해결책이 가장 확실한 해결책이지만 대부분의 독자가 한글윈도에서 도스창을 이용하는 상황이므로 1,2,3번 해결방법은 더 이상 거론하지 않겠습니다.

따라서 4, 5, 6번 방법 중에 하나를 선택해야 합니다. 한 가지 알아둘 점은 테두리선문자 깨짐 현상을 없애려면 한글을 꺼놓아야 하고 이 말은 한글을 입력할 수 없는 상태가 된다는 점입니다. 즉 소스 파일을 작성할 때 한글을 사용할 수 없습니다. 한글 프로그램을 꺼놓은 상태에서는 [한/영] 키를 눌러도 한글이 나오지 않습니다.

(3) 한글윈도의 도스창에서 영문도스 상태로 변환하는 방법


세 가지 방법 중에서 가장 쉬운 방법은 6번입니다. 다음과 같이 합니다.

1. 한글도스창을 실행시킵니다.

2. 도스 상태에서 다음과 같이 명령을 내립니다.

hcode /e



**사진: 도스 상태에서 'hcode /e' 명령을 내립니다.

3. 위와 같이 명령을 내리면 한글도스창이 영문도스 상태로 바뀝니다. 따라서 dir을 비롯한 모든 명령을 내려도 한글로 표시되지 않고 영문으로 표시됩니다. 물론 한글은 깨져서 나옵니다. 한글은 당연히 사용하지 못합니다. hcode /e라는 명령을 내린 후에는 한/영키가 먹지 않습니다.

4. 이제 터보C나 볼랜드C를 실행시키면 테두리선문자가 깨지지 않고 나옵니다.



**사진: TC에서 테두리선 문자가 깨지지 않고 나타납니다.



**사진: BC에서 테두리선 문자가 깨지지 않고 나타납니다.

5. 다시 한글을 쓰고 싶다면 도스 상태에서 다음과 같이 명령을 내립니다.

hcode /k



**사진: 도스 상태에서 'hcode /k' 명령을 내립니다.

6. 이 명령을 내리면 다시 한글을 사용할 수 있습니다. [한/영] 키를 이용해보면 한글입력 상태로 전환되는 것을 볼 수 있습니다. 물론 이 상태에서는 테두리선문자가 깨져서 나옵니다.

참고로 말씀드리자면 한글윈도의 한글 영어 전환키는 보통 스페이스바 오른쪽에 있는 [한/영] 키이거나 오른쪽의 [Alt]키입니다. 한 번 누르면 영어가 써지고, 다시 한 번 누르면 한글이 써지는 똑딱방식(토글방식)으로 사용합니다.

한글윈도를 사용하는 위에서 설명한 방법대로 하시면 테두리선 깨짐 현상을 없앨 수 있지만 한글을 사용하지 못한다는 점을 기억하셔야 합니다.

(4) 도스창에서 'hcode /e'나 'chcp 437'이 안 먹는 경우의 해결방법


앞서 설명한 것처럼 윈도에서 영문상태를 쓰기 위해서는 'hcode /e'라는 명령을 내리면 되고, 한글상태를 사용하려면 'hcode /k'라는 명령을 내리면 됩니다.

만약 'hcode /e' 명령어를 입력했는데도 영문상태로 바뀌지 않는다면 다음과 같은 명령어를 사용해보기 바랍니다. chmod와 chcp 명령어는 hcode처럼 한글코드를 바꾸는 명령인데 hcode보다는 좀더 강력합니다.

chmod 437

또는

chcp 437

chcp 437(또는 chmod 437)은 한글 바이오스 제거 기능을 수행합니다. 반대로 한글 바이오스를 사용하려면 chcp 949라고 명령 내립니다. 다음의 경우가 한글 바이오스를 사용하고자 할 때 내리는 명령입니다. 즉 다음 명령을 내리면 한글 입력이 가능한 한글상태로 전환됩니다.

chmod 949

또는

chcp 949

그런데 chmod 명령을 내렸을 경우에는 '명령 또는 파일 이름이 올바르지 않습니다' 라는 안내문이 나타날 수 있습니다. 이 경우 chmod라는 파일을 찾지 못했기 때문에 발생합니다. 그리고 chcp 명령을 사용했을 때는 '시스템에 437 코드 페이지가 준비되지 않았습니다.'라는 안내문이 나타날 수 있습니다.

이런 경우에는 시스템이 부팅할 때 시스템 설정 파일에 잘못된 내용이 기록되어 있기 때문에 발생합니다.

'hcode /e'라는 명령어가 제대로 먹지 않는다면 config.sys 와 autoexec.bat 파일 안에 country.sys와 nlsfunc.exe에 대한 설정이 제대로 되지 않은 경우입니다.

우선 config.sys 파일에 biling.sys가 제대로 동작하도록 설정되어 있어야 합니다. 만약 윈도95/98이 설치된 디렉토리가 c:\windows라면 다음과 같이 적혀 있어야 합니다.

devicehigh=c:\windows\biling.sys

또는 아래와 같이 적습니다.

device=c:\windows\biling.sys

그리고 autoexec.bat 파일에는 country.sys가 설정되어 있어야 합니다. 따라서 autoexec.bat에는 다음과 같이 설정된 부분이 있어야 합니다.

lh nlsfunc.exe c:\windows\country.sys

또는

loadhigh c:\windows\command\nlsfunc.exe c:\windows\country.sys

위와 같이 config.sys와 autoexec.bat에 설정이 제대로 되었다면 재부팅한 후에 다시 'hcode /e'나 'chcp 437' 명령어를 내려보기 바랍니다. 설정이 제대로 되었다면 제대로 동작합니다.(99%는 동작됩니다.)

만약 이렇게 해도 제대로 동작이 안 된다면 경로가 잘못 지정된 경우로 볼 수 있습니다. 예컨대 가장 많이 실수하는 경우가 nlsfunc.exe의 경로를 잘못 지정하는 경우입니다. 많은 경우 autoexec.bat에 'loadhigh c:\windows\nlsfunc.exe c:\windows\country.sys'와 같이 명령을 주는데 nlsfunc.exe 파일은 windows 디렉토리에 있지 않고 그 밑의 command 디렉토리에 있습니다. 그러므로 파일이 있는 경로를 확인하고 정확하게 경로를 적어주어야 합니다.

만약 윈도 사용자가 앞서 말한대로 config.sys와 autoexec.bat를 제대로 설정했는데도 계속 한글 모드로만 나온다면 system.ini를 한 번 고쳐보기 바랍니다.

system.ini의 [386Enh] 부분에 device=*mshbios 이라고 적혀 있으면 맨 앞 부분에 rem을 덧붙여서 활성 상태를 막아두거나 mshbios를 삭제하는 방법을 사용합니다. 즉 그 줄의 문장이 다음과 같이 되어야 합니다.

rem device=*mshbios

만약 지금까지 제가 설명한 방법으로도 영문모드가 설정되지 않는다면 그때는 더 이상 손쓸 방법이 없습니다. 윈도를 처음부터 다시 설치해야 합니다.

23.1.2. 볼랜드사의 C언어 프로그램 계보는?


[질문] 볼랜드사에서 출시한 C언어 컴파일러 프로그램의 계보는 어떻게 되나요?

[답변]
C언어의 계보는 C > C++ 로 발전했습니다. 이후 MS사에서 만든 C#이라는 언어가 나오긴 했지만 C#이 C++보다 발전된 언어라고 말할 수는 없습니다. 또한 C++을 개선하고 계승한 언어라고 말하기도 곤란합니다. C++은 C를 계승한 언어라고 말할 수 있지만 C#은 자바의 경쟁 상대로 출현한 언어로 볼 수 있기 때문입니다.

볼랜드사의 C언어 관련 컴파일러 프로그램은 터보C > 터보C++ > 볼랜드C++ > C++ 빌더 순으로 발표되었습니다. 현재 주력 상품은 당연히 최근 출시된 C++ 빌더가 되겠죠. 자세한 내용은 볼랜드사의 홈페이지를 참고하기 바랍니다.

23.1.3. 터보C는 공개용 프로그램인가요?


[질문] 터보2.01을 인터넷에서 다운 받았는데요. 이거 제약 없이 사용할 수 있는 공개용인가요? 아니면 상용인가요?

[답변]
터보2.01은 상용입니다만 볼랜드사에서 판매를 중단하면서 공개했습니다. 공개했다는 말은 인터넷을 통해 무료로 배포한다는 뜻입니다. 따라서 이 프로그램을 다운받아서 사용하는 것은 문제가 없습니다. 그렇지만 다운받은 프로그램을 판매하는 경우에는 법률에 위반됩니다.

23.1.4. 볼랜드C++은 공개용 프로그램인가요?


[질문] 볼랜드사 제품에서 볼랜드C++ 3.1을 인터넷에서 다운 받았는데요. 이거 제약 없이 사용할 수 있는 공개용인가요? 아니면 상용인가요?

[답변]
볼랜드C++ 역시 상용이며 볼랜드사에서 아직 정식으로 공개하지 않은 프로그램입니다. 따라서 상용으로 보셔야 합니다.
그렇지만 볼랜드C++ 3.1의 경우 판매가 중단된지 오래 되었으며 국내에서 각종 책의 부록으로 배포했기 때문에 사실상 공개된 상태로 배포중입니다. 지금도 국내 출판사의 자료실 등에 볼랜드C++이 등록되어 있는 상태입니다. 이 때문에 현재로서는 볼랜드C++도 누구나 내려받아 사용할 수 있는 사실상의 공개용 프로그램이 되었습니다. 그렇지만 기본적으로는 상용 제품이라는 점을 잊기 말기 바랍니다.

23.1.5. 터보C하고 터보C++이 공개라는데 어디서 구할 수 있나요?


[질문] 터보C와 터보C++이 공개라고 하셨는데 어디에서 다운로드 받을 수 있나요?

[답변]
터보C 2.01과 터보C++ 1은 현재 볼랜드사에서 공개한 상태입니다. 따라서 볼랜드사의 사이트를 통해서 내려받을 수 있습니다. 자세한 방법과 주소는 책 본문에 설명된 내용을 참고하기 바랍니다.

23.1.6. 볼랜드사의 기타 공개 프로그램과 다운로드 주소는?


[질문] 볼랜드사에서 터보C 2.01, 터보C++ 1.0 외에 공개한 프로그램과 이들 프로그램을 다운로드 받을 수 있는 주소를 알려주세요.

[답변]
주소가 수시로 바뀌는 관계로 책을 통해서 각 프로그램의 주소를 알려드리기는 곤란합니다. 제 개인 홈페이지인 www.help119.com에 접속하면 프로그램을 받을 수 있는 최신 주소를 볼 수 있습니다.

23.1.7. 리눅스용 컴파일러와 다운로드 주소


[질문] 리눅스용 C언어 컴파일러로는 어떤 것이 있으며 어디에서 다운로드 받을 수 있나요?

[답변]
리눅스용 C언어(C++) 컴파일러로 가장 유명한 것은 역시 GCC입니다. GCC는 GNU 그룹에서 공개한 컴파일러입니다. GNU 그룹은 잘 알려진 것처럼 정보 공유를 위해 노력하는 단체로 리눅스 역시 이 단체에 의해서 배포되고 있습니다. GCC는 GNU에서 배포하는 것이므로 C(C++) 컴파일러로서의 성능이나 가치는 어지간한 상업용보다 낫다고 할 수 있습니다.

GCC 컴파일러는 GNU 홈페이지에서 다운로드 받을 수 있습니다. 현재 GCC는 3.2판이 배포중인데 버전 변화에 따라 파일의 다운로드 주소가 바뀔 수 있습니다. 따라서 최신판의 주소는 제 홈페이지를 이용하기 바랍니다. 제 홈페이제 접속하면 최신판의 주소와 한국 내 FTP 서버 주소, 기타 주소에 대한 정보를 얻을 수 있습니다.

또는 GNU 공식 홈페이지를 이용하면 됩니다.

* GNU 홈페이지(http://www.gnu.org/)
* GCC 홈페이지(http://gcc.gnu.org/)

23.1.8. 볼랜드사의 컴파일러를 학생판으로 싸게 구입할 수 있나요?


[질문] 볼랜드사의 C++ 컴파일러 가격을 보면 몇 백만원이나 하네요. 공부하기 위한 학생을 위한 버전은 없나요? 학생판으로 싸게 구입하면 얼마나 하나요?

[답변]
볼랜드사에서는 2002년 하반기부터 정책을 바꾸어 모든 볼랜드사 제품의 관리와 지원을 볼랜드코리아에서 맡고 있습니다.

현재 볼랜드사에서는 2002년 9월 23일부터 학생판 버전을 출시했습니다. JBuilder, Delphi, C++Builder, Kylix등을 매우 싼 가격에 제공하는데, C++빌더는 59,400원에 제공합니다.

단 이들 제품은 학생만 사용 가능하며 학생이라 하더라도 상용 제품 개발에 사용하지 못합니다. 그러나 공개용 프로그램 제작에는 사용할 수 있습니다. 학생들이 공부용으로 구입해 쓸 수 있는 가격이므로 볼랜드사의 C++ 컴파일러를 구입하고 싶다면 이 제품을 구입해 C++을 공부하기 바랍니다.

이들 제품에 대한 정보와 구입은 볼랜드 코리아 홈페이지에서 볼 수 있습니다. 현재 이 제품의 판매는 볼랜드 익스퍼트 사이트에서 볼 수 있는데 볼랜드 익스퍼트 사이트가 계속 유지될지 여부는 불확실합니다. 이전에 제품 판매를 담당했던 인프라이즈 사이트가 폐쇄된 적이 있거든요. 만약 볼랜드 익스퍼트 사이트가 폐쇄된다면 제 홈페이지에 링크된 내용을 참고하여 판매처를 알아보기 바랍니다.

23.1.9. 터보C 설치 때 다음 디스켓 넣으라는 안내문에서 막힙니다.


[질문] 다운받은 터보C를 설치하다가 다음 디스켓을 넣으라는 과정에서 막힙니다.

[답변]
터보C 설치 방법은 책 본문에서 충분하게 설명하고 있습니다. 가장 기본적인 방법은 플로피디스크에 각기 파일을 복사한 다음에 디스켓을 갈아끼우는 방법입니다. 그 방법이 귀찮을 경우에는 각 디렉토리로 구분되어 있는(disk1, disk2 디렉토리로 구분되어 있을 겁니다) 파일을 모두 하나의 디렉토리로 복사한 뒤에 설치하면 됩니다. 설치 파일을 하나의 디렉토리로 복사한 다음에 설치하는 방법도 본문에 자세하게 설명해두었습니다. 책 본문을 참고하여 설치하기 바랍니다.

23.1.10. 터보C에서 한 번 설정한 환경을 그대로 유지하려면?


[질문] 터보C를 끝내고 다시 실행시키고 끝내면 이전에 사용한 환경으로 동작하지 않아, 사용할 때마다 directories환경을 매일 다시 설정하고 있습니다. 디렉토리 환경을 계속 유지하려면 어떻게 해야 합니까?

[답변]
터보C의 경우 한 번 설정한 환경을 그대로 계속 사용하려면 환경설정 파일을 저장해야 합니다. 환경설정 파일을 저장하는 방법은 책 본문에 적혀 있으니 참고하기 바랍니다. 환경설정 파일을 Save options 메뉴를 이용해 저장하면 한 번 설정한 디렉토리 환경을 그대로 사용할 수 있습니다.

23.1.11. 컴파일러가 다르면 C 문법도 다른가요?


[질문] C를 지원하는 컴파일러의 수가 많은데 컴파일러에 따라 C의 문법도 달라지나요? 같은 언어라도 컴파일러에 따라 문법을 다르게 작성해야 하는지 궁금합니다.

[답변]
C의 경우 수 백 종류의 컴파일러 프로그램이 있습니다. 각기 다른 컴파일러 프로그램은 각기 다른 라이브러리를 제공합니다. 따라서 함께 제공되는 라이브러리를 사용하려면 컴파일러 프로그램에 맞게 프로그램을 작성해야 합니다. 그렇지만 C의 기본 함수만 사용할 때는 컴파일러 프로그램에 상관하지 않고 만들 수 있습니다.
[C언어 이야기]를 보면 똑 같은 프로그램을 가지고 터보C, 볼랜드 C++, 비주얼 C++에서 컴파일해 사용하는 것을 볼 수 있습니다. 이는 C의 기본 함수와 문법만 사용했기 때문입니다.

기본적으로 컴파일러가 다르다고 해서 C의 문법을 달리해 프로그램을 만들지 않습니다. 같은 소스를 가지고 각기 다른 컴파일러로 컴파일해 파일을 만들 수 있습니다.

다만 해당 컴파일러에서만 지원하는 기능을 사용하고자 할 때는 문법 내용이 달라집니다. 그래픽을 사용할 경우에는 해당 컴파일러의 라이브러리를 사용해야 하므로 호환성이 크게 떨어집니다. 즉 해당 컴파일러 전용 함수를 사용하면 문법이 달라지지만 C의 기본 문법을 이용해 프로그램을 작성한다면 컴파일러 특성을 안탑니다.

23.1.12. 터보C나 볼랜드C++ 로 만든 소스 파일을 비주얼C++에서 컴파일할 수 있나요?


[질문] 집에서 비주얼C++을 사용하는데 터보C나 볼랜드C++로 만든 소스 파일을 비주얼C++로 가져와 컴파일할 수 있나요?

[답변]
소스 파일의 내용에 따라 될 수도 있고 안될 수도 있습니다. 각 컴파일러는 지원하는 함수와 문법, 라이브러리 파일이 다릅니다. 따라서 터보C에서만 지원하는 문법과 라이브러리 함수를 사용해 만든 예제는 비주얼C++에서 컴파일할 때 오류가 발생합니다.

단 C의 기본 문법만을 이용해 만든 예제라면 터보C, 볼랜드C++, 비주얼C++에서 모두 사용 가능합니다. 예를 들어 [C언어 이야기]의 예제는 C언어의 기본 문법만을 사용해 만든 것이라 대부분의 컴파일러 프로그램에서 이상 없이 컴파일할 수 있습니다. [C언어 이야기]의 예제는 몇몇을 제외하면 터보C, 볼랜드C++, 비주얼C++에서 모두 컴파일할 수 있습니다.

그렇지만 대개의 프로그램은 터보C에서 컴파일된 소스 파일을 비주얼C++에서 컴파일할 경우 오류가 발생합니다. 대부분 해당 컴파일러에서만 지원하는 전용 함수나 라이브러리를 사용해서 프로그램을 만들기 때문에 다른 컴파일러에 가져가 컴파일하면 오류가 발생합니다.

23.1.13. 도스용 볼랜드C++로 윈도용 프로그램을 만들 수 있나요?


[질문] 도스용 볼랜드C++을 사용하고 있습니다. 이것으로 윈도용 프로그램을 만들 수 있나요?

[답변]
기본적으로 도스용으로는 윈도용 프로그램을 만들 수 없습니다. 단 윈도용 라이브러리와 커맨드 방식의 컴파일러가 함께 제공된다면 가능합니다. 그러나 사용법이 까다롭기 때문에 윈도용 프로그램을 사용하는 것이 훨씬 편합니다.

23.1.14. 자신이 사용하는 컴파일러 프로그램에 예제 파일이 없는 경우


[질문] 제가 설치한 터보C에는 예제가 없습니다. 어디서 구할 수 있나요?

[답변]
인터넷을 통해 터보C를 구한 사람 중에는 예제가 빠진 불완전한 상태의 터보C를 구한 경우가 있습니다. 주로 개인이 사용하던 터보C 디렉토리를 통채로 압축해 올린 파일을 내려받은 경우입니다.

예제가 없을 경우에는 완전한 터보C를 구해 다시 설치하는 것이 좋습니다. 이 책에는 터보C를 구하는 방법과 설치하는 방법을 설명해두었습니다. 책 본문의 터보C 구하는 방법을 참고하기 바랍니다. 만약 책 본문의 주소가 바뀌었을 경우에는 제 홈페이지인 www.HELP119.com으로 접속해 문의하기 바랍니다.

23.1.15. 리눅스용gcc에서 그래픽을 처리하려면?


[질문] 리눅스에서는 gcc compiler로 ansi-c 표준 정도밖에 지원되지 않는데 를 사용한 프로그램은 어떻게 컴파일해야 되나요?

[답변]
graphic.lib 는 터보C에서만 제공되는 라이브러리이고 도스용이기 때문에 리눅스에서 사용할 수 없습니다. 리눅스용 C컴파일러인 gcc를 사용한다면 gcc용 그래픽 라이브러리를 따로 구해서 사용법을 익혀야 합니다. 즉 운영체제에 따라서 각 운영체제에서 사용하는 컴파일러가 다르고 해당 컴파일러에 맞는 그래픽 라이브러리 파일을 따로 구해서 사용해야 하는 것입니다.

23.1.16. 주석 달 때 한글 글꼴이 옆으로 누워서 보이는 이유와 해결 방법


[질문] 볼랜드C++ 3.1을 이용해 주석을 한글로 달려고 하면 글씨가 옆으로 누운 것처럼 쓰여집니다. 왜 그럴까요?

[답변]
한글이 옆으로 누운 것처럼 나타나는 현상은 윈도의 문제입니다. 즉 볼랜드C++의 문제가 아니고 윈도의 글꼴 파일과 관련된 문제입니다. 다른 프로그램에서도 이러한 현상이 발생할 수 있습니다. 글꼴 문제이므로 좀더 정확한 해결을 위해서는 마이크로소프트사의 고객상담실에 문의해 해결하기 바랍니다.

일단 볼랜드C++ 에서의 해결방법만 알려드립니다. BCW를 실행시킨 후에 메뉴에서 [Options ] - [Enviroment] - [Preferences] -[ Font] 순으로 선택합니다. 글꼴 이름 앞에 보면 골뱅이가 붙은 글꼴이 선택되어 있을 경우 글씨가 옆으로 눕습니다. 즉 @굴림체10이라고 써진 글꼴이 선택될 경우 글씨가 90도 회전한 형태로 표시됩니다. 골뱅이가 없는 다른 글씨를 선택하면 해결됩니다. 굴림체10을 선택하면 해결되는 것이죠.

23.1.17. 여러 개의 예제 창을 닫는 방법과 다음 실행 때 예제가 안 불러오게 하는 방법은?


[질문] 예제를 여러 개 하면 창이 여러 개 나옵니다. 어떻게 해야 다 닫을 수 있나요? 그리고 이전에 불러왔던 예제가 안나왔으면 하는데 어떻게 하면 이전에 불러온 예문이 안나올까요?

[답변]
볼랜드C++은 이전에 사용한 예제 파일을 기억했다가 모두 창으로 열어줍니다. 다음 실행 때 이런 창이 안나오게 하려면 사용했던 창을 모두 닫아준 뒤에 프로그램을 끝내면 됩니다.

창을 닫는 메뉴는 'Windows'메뉴를 선택하고 'Close' 메뉴를 선택하면 됩니다. 'Close All'을 선택하면 한꺼번에 모든 창이 다 닫힙니다. 따라서 예제를 마친 후에는 'Windows'메뉴를 선택하고 'Close' 메뉴를 선택해 창을 닫으시면 다음 번에 해당 예제 창이 뜨지 않습니다.

23.1.18. 도스창에서 실행한 프로그램이 종료 후 자동으로 도스창 안닫게 하려면?


[질문] 컴파일 후 실행 파일을 윈도 도스창에서 실행시키면 실행 후 바로 도스창이 닫힙니다. C언어에도 실행 파일로 만든 후에 윈도 도스창에서 실행 후 결과창이 열려있게 하는 명령어가 있나요?

[답변]
도스용 프로그램을 윈도 도스창에서 실행시킬 경우 자동으로 도스창이 닫히는 이유는 윈도의 도스창 환경 설정을 그렇게 했기 때문입니다. C언어하고 관련된 기능이 아니고 윈도의 사용법과 관련된 문제입니다.

윈도의 도스창 아이콘에서 마우스 오른쪽 단추를 누른 뒤 등록정보를 선택하고 [프로그램]을 선택하면 [종료시 창 닫기]라는 부분에 선택 표시가 되어있을 겁니다. 이 부분을 선택하지 않으면 프로그램 종료 후에도 도스창이 닫히지 않습니다.

그리고 화면 출력 결과를 보고자 할 때 어떤 화면 출력 결과물을 보여준 뒤에 잠시 멈추게 하려면 getch() 함수를 사용합니다. 이렇게 하면 엔터키나 기타 키를 입력하기 전까지 화면이 정지되므로 연습 문제를 만들어 터보C안에서 실행할 때 유용하게 사용할 수 있습니다. getch() 함수 사용법은 책 본문에 있습니다.

23.1.19. 선언한 배열 첨자 이상을 접근할 때 컴퓨터가 먹통이 안되게 하는 컴파일 옵션이 있나요?


[질문] 선언한 배열 첨자 이상을 접근할 때 컴파일 과정에서 에러가 났는데요, 프로그램을 실행하면 컴퓨터가 먹통이 됩니다. 컴퓨터가 먹통이 안되게 하는 컴파일 옵션이 있나요?

[답변]
배열처럼 메모리에 접근하는 프로그램을 짜는 경우에는 사용하는 번지의 범위를 벗어나지 않는 한도에서 짜는 것이 정답입니다. 컴파일러는 문법적인 몇몇 오류에 대해서는 어느 정도 경고문을 보여주지만 모든 오류에 대하여 경고해주는 것이 아닙니다. 프로그래머가 a+b라는 수식을 써야 하는데 이를 실수로 a*b로 하거나 a/b로 했을 경우에도 컴파일러는 컴파일할 때 오류를 보여주지 않습니다. 그렇지만 실제로 컴파일된 실행 파일을 수행시키면 컴퓨터가 먹통이 되는 경우가 허다합니다.

따라서 논리적인 오류가 없도록 소스 파일을 바르게 작성하는 것이 가장 좋은 해결책입니다. 컴파일러의 옵션 조정으로 논리적인 오류를 없애려는 것은 편법이며 위험한 방법입니다.

23.1.20. 스크롤 되어 넘어간 화면은 어떻게 보나요?


[질문] 프로그램을 만들어 실행할 때 출력물이 너무 길면 화면이 넘어가는데 그 넘어간 것을 다시 볼 수가 없어요. 스크롤바도 안생기구. 어떻게 해야 출력물을 다 볼 수 있나요?

[답변]
스크롤바가 안 생기는 것은 모든 프로그램에 공통되는 사항입니다. 화면이 넘어간 내용을 다시 보지 못하는 것은 당연합니다. 도스에서는 스크롤 된 것을 다시 볼 수 있는 방법이 없고, 윈도에서도 스크롤바가 안 움직이면 방법이 없습니다.
따라서 출력물을 모두 보면서 프로그램을 진행하게 하려면 화면 크기에 맞게 출력물을 표시한 다음에 화면 스크롤을 정지시키는 방법을 이용해야 합니다. 이에 사용하는 대표적인 함수가 getch() 함수입니다. getch() 함수 사용법은 본문에 설명한 내용을 참고하기 바랍니다.

23.2. 문법 관련 질문


23.2.1. word, bool, cord 등의 자료형은 어디에 사용합니까?


[질문] 다운 받은 예제 소스를 보면 int, float 라는 일반적인 자료형 외에도 word, bool, code 등의 자료형이 있는데 이들 자료형도 C언어에서 지원하는 자료형인가요? 이들 자료형은 어디에 사용하나요?

[답변]
word나 bool 등은 C에서 지원하는 기본 자료형이 아닙니다. 이들은 사용자 정의 자료형으로 보시면 됩니다. 즉 선행처리기 명령인 #define 명령에 의해서 만든 자료형입니다.

그럼 왜 이런 자료형을 만들어 사용할까요? 운영체제나 컴파일러 사이의 호환성을 높이기 위해서입니다.

예컨대 int, long, double, char 등의 기본 자료형은 컴퓨터나 운영체제에 따라서 저장 길이가 달라집니다. IBM PC에서 운영체제로 도스를 사용할 경우에는 int가 2바이트로 저장되지만 유닉스 등에 가면 저장되는 길이가 달라집니다. 대형 컴퓨터인 VAX의 경우 int가 4바이트의 크기로 저장됩니다. 따라서 A라는 컴퓨터에서 int라는 이름으로 변수를 선언한 소스 파일을 B라는 컴퓨터에 가져가서 컴파일할 경우 숱한 오류가 발생합니다. VAX에서는 int 형이 4바이트의 크기를 가지는데 IBM PC로 가져오면 2바이트로 바뀌기 때문입니다. IBM PC에서는 long 형이 4바이트의 정수형 자료형이 됩니다. 따라서 VAX에서 작성한 것을 IBM PC에서 컴파일할 경우 int 형을 모두 long형으로 바꾸어주어야 합니다. 그러나 이는 매우 어려운 작업입니다. 우선 수 백 개의 소스 파일을 일일이 뒤져서 바꾸는 일도 어렵고, 원래 소스에서 long 형으로 선언한 부분의 처리 문제도 걸리기 때문입니다.

이런 경우 가장 좋은 해결방법은 선행처리기를 이용하는 방법입니다. 예를 들어 헤더를 모은 소스 파일에 '#define FOUR int' 라는 명령을 주고, 소스 파일에서 변수를 선언할 때 FOUR x=3; 과 같은 형태로 사용합니다. 이렇게 하면 FOUR x=3;은 선행처리기에 의해 int x=3;으로 치환되죠. 그리고 이 소스 파일을 IBM PC에서 컴파일할 때는 한 줄만 고치면 아무 오류 없이 실행됩니다. '#define FOUR long' 이라고 고치면 됩니다. 그러면 FOUR x=3 명령은 long x=3으로 치환됩니다. #define 명령의 사용법에 대해서는 [C언어 이야기]읜 본문 내용을 참고하면 됩니다.

마찬가지 이유로 char이라는 자료형도 컴퓨터와 운영체제, 컴파일러에 따라서 크기가 달라집니다. 그래서 char 대신 word라는 낱말을 이용하는 경우가 많습니다.

bool은 불린 상수를 뜻하는 자료형으로 사용합니다. 즉 0이나 1 중의 하나를 선택하는 자료형입니다.

0이나 1 중의 하나를 선택하는 자료형이라면 int형 자료형으로 충분히 다룰 수 있습니다. 그런데도 bool 자료형을 따로 만드는 이유는 사용의 편리를 위해서입니다. int x=0이라는 명령만으로는 참 거짓을 다루는 불린형 자료인지 알기 힘듭니다. x의 값은 0부터 65535까지 넣을 수 있기 때문에 x의 값으로 2나 3도 쓸 수 있다고 판단합니다.

그렇지만 bool x=0이라는 명령을 보면 x의 값으로 0이나 1중에 하나만 써야 한다는 사실을 바로 알 수 있죠. 이처럼 자료형이 다양해질 경우 프로그램을 판독하기가 한결 쉬워지며, 호환성이 높아집니다.

때문에 어떤 경우에는 컴파일러에서 word나 bool이라는 자료형을 기본적으로 지원할 수도 있습니다. 그렇지만 많은 경우 word나 bool 등은 프로그래머가 만들어 사용하는 사용자 정의 자료형인 경우가 많습니다. 따라서 컴파일러에서 지원하는 기본 자료형이라면 컴파일러의 도움말을 참고하면 되고, 사용자 정의 자료형일 경우에는 선행처리기 명령 부분을 참고하면 됩니다.

23.2.2. 실수형 변수가 정수형으로 출력되지 않는 이유는?


[질문] 아래와 같은 예제를 만들었습니다.

#include <stdio.h>

main()
{
int i;
float f;

f=1234.0098;
i=f;

printf("%d %d", f, i);
}

위와 같은데요... f의 값은 어떤지 모르더라도 i의 값이 1234를 출력해야 하는데 실제 결과는 0을 출력하더군요. 왜 그렇죠?

[답변]
소스 파일 중에서 i=f; 까지 이상 없습니다. 여기까지 과정을 통해 i=1234가 되었습니다.

문제가 되는 부분은 출력문 부분입니다.

printf("%d %d", f, i);

이와 같이 출력할 경우 첫 번째 %d에 실수인 f 변수의 내용이 제대로 대입되지 않습니다. f 변수는 자신의 자료형에 맞는 대입기호인 %f가 나올 때까지 변수를 검색하게 됩니다. 그러나 %d %d로 모두 정수형 변수를 대입해야 하기 때문에 f는 출력문을 무시하게 됩니다. 두 개의 %d 기호를 모두 흘려보내는 것이죠. 따라서 %d %d는 모두 0으로 나옵니다. 그리고 f가 대입되지 않은 까닭에 i가 대입될 순서가 오지 않은 것이고요.

다음과 같이 변수의 대입순서를 바꾸어보면 쉽게 이해됩니다. vprintf("%d %d", i, f);

i는 정수형 변수이기 때문에 첫 번째 %d에 대입되어 1234가 출력됩니다. 그러나 두 번째 %d에 f가 대입될 수 없겠죠. 그래서 두 번째는 0으로 출력됩니다.

따라서 변수가 제대로 출력이 되기를 원한다면 대입기호로 정확한 자료형을 연결시켜주어야 합니다. 다음과 같은 세 가지 방법 중에서 하나를 선택해야 하죠.

(1) 가장 기본적인 방법 : 맞는 자료형을 연결시킨다.

printf("%f %d", f, i);

이렇게 하면 1234.009766 1234가 출력됩니다.

(2) 캐스트 연산자를 이용해 잠깐 동안 f를 정수로 변환한다.

printf("%d %d", (int)f, i);

이렇게 하면 1234 1234가 출력됩니다.

(3) 출력순서를 바꿀 경우 하나는 제대로 출력된다.

printf("%d %d", i, f);

이렇게 하면 1234 0이 출력됩니다.

변수나 자료를 출력할 때는 자료형의 형태와 순서, 갯수 중에서 하나만 틀려도 엉뚱한 결과를 나타냅니다. 그래서 주의가 필요한 것이죠.

23.2.3.제곱 구하기 함수에서 큰 수를 제곱했을 때 엉뚱한 결과로 나오는 이유


[질문] "변수를 이용해 제곱수를 구하는 프로그램"을 만들어 실행한 다음에 3을 입력하면 9가 나오고, 4를 입력하면 16이 나옵니다. 그런데 왜 256을 입력하면 0이 나오죠? 잘 이해가 안됩니다.

[답변]
결론을 말씀 드리면 결과를 보여주는 변수 b의 자료형이 int형(정수형)이기 때문입니다. 책을 좀더 읽어보면 자료형에 대한 설명이 나옵니다. 이 부분을 읽어보면 왜 그런 결과가 나왔는지 알 수 있습니다. 또한 256을 곱했을 때 0이 나오는 이유도 이해할 수 있습니다.

int a,b; 라는 명령문은 자료형을 정수로 선언한다는 뜻입니다. 정수형 자료형은 저장할 수 있는 숫자의 범위가 0부터 65535까지 또는 -32768~32767까지만 저장할 수 있습니다. 그래서 두 수를 제곱한 결과값이 이 범위를 넘어설 경우 변수 b에는 엉뚱한 값이 대입됩니다.

그러니까 1000*1000을 할 경우 백만이라는 숫자가 나오는데 이렇게 큰 수는 int형 변수에 저장이 불가능합니다. 이럴 경우에 엉뚱한 숫자가 계산 결과로 나오게 됩니다.

만약 256*256 또는 1000*000을 했을 때도 제대로 값이 나오게 하려면 변수의 자료형을 큰 수를 저장할 수 있는 자료형으로 지정해야 합니다. 예제에서 int a 대신에 float a; 또는 double a;라고 고치면 큰 수의 곱도 제대로 계산해 보여줍니다.

23.2.4.123.45가 123.459997로 출력되는 이유


[질문] 제가 짠 프로그램은 다음과 같습니다.

#include <stdio.h>
#include
viod main ()
{
float a = 123.45;
doubel b = 123.45;
printf("%f,%f\n",a,b);
getch();
}

실행하니 출력이

a=123.44444447과

b=123.45

이렇게 나오는 이유를 모르겠습니다

a,b 둘 다 123.450000 가 나올 줄 알았는데 a가 123.44444447이 나오는 이유와 b가 123.45로 나오는 이유를 모르겠습니다. 이유를 알려주시면 고맙겠습니다.

[답변]
우선 소스 파일에 여전히 문제가 있습니다. 거듭 말씀드리지만 컴파일이 되는 것이 이상합니다. void라고 적어야 할 부분이 viod로 적혀 있고, double로 적어야 할 낱말은 double로 적혀 있습니다. 이런 상태라면 제대로 출력될 수 없습니다. 앞서 제가 올렸던 소스 파일대로 적어서 컴파일해보기 바랍니다.

#include <stdio.h>
#include
void main(void)
{
float a = 123.45;
double b = 123.45;
printf("%f\n %f\n",a,b);
getch();
}

제가 만든 소스 파일대로 컴파일한다면

a=123.449997
b=123.450000

이라는 답이 나와야 합니다.

b가 123.45가 아닌 123.450000으로 뒤에 0이 네 자리 더 붙은 이유는 컴파일러에서 기본값으로 지정한 소수점 이하의 자릿수가 여섯 자리로 지정된 까닭입니다. 이는 printf() 함수에서 자릿수를 조정함으로써 원하는 자리로 조정이 가능합니다.

그리고 a가 123.449997이라는 엉뚱한 답이 나오는 까닭은 실수형 자료형이 지수부와 가수부를 이용해 저장하기 때문입니다. 실수형 자료형의 최대정밀도와 유효정밀도의 값이 다르게 나타나는 이유에 대해서는 책 본문의 자료형에 대한 부분에서 설명해놓았습니다. 책 본문의 실수형 자료 설명 부분에 자세하게 설명되어 있으니 이 부분을 참고하기 바랍니다.

유효정밀도를 높이기 위해서는 소수점 이하의 자릿수를 조정하는 기술이 필요합니다. 예를 들어서

printf("%7.2f %f\n",a,b);

와 같이 자릿수를 조정하면 a도 123.45라고 제대로 출력되어 나옵니다. 자릿수 조정에 관한 내용은 printf() 함수 설명 부분에 자세하게 적어 놓았으니 이 부분을 참고하기 바랍니다.

23.2.5.float형보다 double형을 많이 사용하는 이유는?


[질문] 프로그램을 짤 때 float형보다 double형을 많이 사용하는 이유는 무엇인가요?

[답변]
실수형은 세 가지 종류가 있습니다. 가장 기본적으로 사용하는 float가 있고, double와 long double가 있습니다. 차이점은 계산 범위입니다. long와 double라는 낱말은 기본형의 값보다 더 큰 범위를 지정할 때 사용하는 낱말입니다.

float는 10의 -38제곱에서 38제곱까지의 숫자를 나타낼 수 있습니다. double는 이보다 훨씬 큰 수인 10의 -308제곱에서 308제곱까지의 숫자를 나타낼 수 있습니다. long double는 이보다 더 큰 10의 -4916제곱에서 4932제곱까지의 숫자를 나타낼 수 있습니다.

우리가 일반적으로 사용하는 숫자는 10의 -38제곱에서 38제곱 범위 안의 숫자를 사용하기 때문에 float 형을 이용해 계산해도 대부분 계산이 가능할 것 같습니다. 그렇지만 실제로는 억 단위가 넘어가는 사칙연산에 사용하는 변수조차도 float형으로 사용하기 곤란합니다.

그 까닭은 최대정밀도와 유효정밀도, 출력정밀도의 차이를 고려하기 때문입니다. 이에 대한 내용은 책 본문에 설명했으니 본문을 참고하기 바랍니다.

간단하게 double를 사용하는 이유만 말하자면 float는 32비트 즉, 4바이트만을 이용해 숫자를 저장하기 때문에 3조 9천억과 같이 지수부와 가수부가 간단한 경우에는 정밀도가 높게 계산할 수 있어 오차가 별로 없습니다. 그러나 가수 부분이 복잡할 경우에는 정밀도가 매우 낮아 계산할 때 많은 오차가 발생하기 때문입니다.

123,456,788,999,012,333처럼 가수부가 길 경우 32비트로 이 긴 숫자를 저장하는 일이 곤란합니다. 0부터 9까지 표현하려면 4비트가 필요하므로 32비트로 저장할 수 있는 숫자의 갯수는 몇 개로 한정됩니다.

때문에 억 단위의 숫자만 사용한다 해도 어느 단위부터는 잘라내야 하는데 이 경우 오차가 발생합니다.

double이나 long double를 사용할 경우 컴파일러에 따라서 조금씩 다르기는 하지만 float형보다 두 배 이상의 저장 공간을 할당합니다. 즉 64비트를 할당하기 때문에 가수부가 길거나 큰 수도 오차를 줄여 저장할 수 있습니다. 조 단위의 숫자도 잘라내는 부분 없이 변수에 바로 저장할 수 있어 오차 없는 계산이 가능합니다. 그래서 대개의 경우 간단한 계산을 사용하는 곳이 아니라면 float형이 아닌 double 형을 사용하기 마련입니다.

23.2.6.long형(정수) * 실수 = long형(정수형). 근데 답이 부정확합니다.


[질문] (long 형으로 선언한 변수)a = b(long형) * 0.7; 이럴 때 b에다 5000을 대입했습니다. 그랬더니 3449가 나오네요. 3500이 안나오고 3449가 나오는 이유는 무엇인가요?

[답변]
[C언어 이야기] 본문을 읽어보면 이해할 수 있는 내용으로 자료형이 다른 것을 사용할 때 발생하는 오차가 원인입니다.

자료형이 다른 것끼리 연산할 때는 연산 결과에 오차가 발생합니다. 특히 실수형과 섞어서 계산할 경우 대개의 경우 오차가 발생합니다.

아래의 프로그램을 실행해보면 오차에 대해서 알 수 있습니다.

#include <stdio.h>

void main(void)
{
long a,b=5000;
float c,d=5000,e=0.0000001,f=0.0001;

a=b*0.7;
printf(" (1) a = %ld \n",a);

a=b*7/10;
printf(" (2) a = %ld \n",a);

a=b/10*7;
printf(" (3) a = %ld \n",a);

c=d*0.7;
printf(" (4) c = %f \n",c);
printf(" (5) c = %ld \n",(long)c);

e=e-1;
e=e+1;
printf(" (6) e = %f \n",e);
printf(" (7) e = %15.10f \n",e);

f=f-1;
f=f+1;
printf(" (8) f = %f \n",f);
}

위 프로그램을 실행하면 (1)번만 3499로 나오고 2~5번은 3500으로 나오죠. 이처럼 1번만 3499로 나오는 이유를 long형과 실수형을 곱했기 때문입니다.

(6)번의 경우 e에서 1을 빼고 1을 더했기 때문에 처음 대입된 0.0000001이 나와야 합니다. 그렇지만 0이 나옵니다. 자릿수 문제 때문인가 싶어 (7)처럼 소수점 10자리까지 출력하면 더욱 해괴한 수가 나옵니다. 0.0000001192라는 터무니 없는 수가 나오죠. 반면 (8)은 제대로 0.000100으로 나옵니다. 이런 문제가 발생하는 이유는 실수형이 지닌 한계 때문입니다. 그래서 제 책에서 연산 결과를 믿지 말라고 적은 것입니다.

컴파일러 프로그램과 C언어의 자료형 자체가 지닌 문제점이라는 점을 인식하고 항상 계산식을 만들 때는 계산의 정확성을 검증하면서 만들기 바랍니다. 물론 long*float형 같은 공식 자체는 사용하면 안됩니다.

23.2.7.왜 C에는 문자열형이라는 자료형이 없는 거죠?


[질문] 문자열형이 있으면 편할 것 같은데, 왜 C에는 문자열형이라는 자료형이 없는 거죠?

[답변]
C에 문자열이라는 자료형이 없는 이유는 문자열 자료형이 따로 필요 없기 때문입니다. 실제로 C에서는 문자열을 사용합니다. 다만 문자열이라는 자료형을 만들어 사용하지 않기 때문에 함수가 아닌 포인터와 배열을 이용한다는 점이 다를 뿐입니다.

C에는 질문하신 문자열 자료형을 비롯하여 몇 가지 없는 것들이 있습니다. 대신 포인터라는 강력한 장점을 추가했습니다. 포인터를 이용하면 거의 모든 자료형을 다 다룰 수 있기 때문에 문자열과 같은 자료형을 따로 만들 필요가 없는 것이죠. 포인터는 C언어가 가진 가장 강력한 장점입니다. 포인터를 공부해보면 문자열이 왜 필요 없는지 저절로 아시게 될 겁니다.

23.2.8.변수 대입을 분수로 하면 안되나요? n=1/3으로 하면 3.33이 아니라 0이 나오네요.


[질문] 부동소숫점형에서.. 변수초기화를 분수 형태로 초기화 할 수는 없나요?

예) double num=1/3;

제곱함수 pow(3.0 , 1/3)이런 형태루 인자를 넘겼더니.. 문제가 되더라구요. 위에 num 값두 0으루 나오구...

[답변]
문제가 발생하는 이유는 자료형을 맞추어주지 않았기 때문입니다. 인수와 자료형에 관한 책의 본문 내용을 좀더 참고하기 바랍니다.

C언어는 자료형에 있어 엄격한 편입니다. 자료형이 다르면 오류가 발생합니다. 즉 다음의 두 명령은 완전히 다릅니다.

n=1/3;

n=1.0/3;

1은 정수형이지만 1.0은 실수형입니다. 그래서 두 명령은 완전히 다릅니다. 이에 대한 내용은 책 본문에서 언급했습니다.

float n; 으로 설정하고 첫 번째 줄의 n=1/3; 명령을 준 다음에 prinft() 함수로 출력해보면 n은 0이 나옵니다. 그렇지만 두 번째 명령인 n=1.0/3; 명령을 준 다음에 출력해보면 0.33333으로 제대로 나옵니다. 즉 문제의 원인은 n 이 실수형으로 선언되었는데도 정수형으로만 계산을 했기 때문에 발생합니다.

이런 문제를 피하려면 형변환 연산자를 사용하거나 자료형의 하나를 실수형으로 사용해야 합니다.

즉 인수에서도 분수를 줄 수는 있지만 1/3 으로 주었기 때문에 오류가 발생하고 0이 된 것입니다. 1.0/3 또는 1.0/3.0 또는 1/3.0 등으로 자료를 넘겨주면 0.3333이 제대로 전달되고 올바른 결과가 출력됩니다.

아래는 자료를 입력할 때 어떤 식으로 입력해야 오류가 나지 않는지 보여주는 예제입니다. 아래의 예제에서 n=1/3.0; 명령을 n=1/3; 으로 하거나 printf("n x m =%f \n\n",gob(1/3.0, 2.0)); 명령의 인수로 1/3을 주면 0으로 결과가 나옵니다.

#include <stdio.h>

float gob(float a, float b){
double re=0;
re=a*b;
return re;
}

void main(void)
{
float n=1, m=1;
printf("n= %f, m=%f \n\n",n,m);
n=1/3.0;
m=5.3;
printf("n= %f, m=%f \n\n",n,m);
printf("n x m =%f \n\n",gob(1/3.0,2.0));
}

23.2.9.실수형은 논리값을 가질 수 없나요?


[질문] 실수형은 논리값을 가질 수 없나요?

[답변]
아닙니다. 모든 자료형은 자체로 논리값을 가집니다.

제 책에서 말한 것처럼 컴퓨터(컴파일러 프로그램)는 0을 거짓으로 1을 참으로 알며, 0 아닌 것은 참으로 압니다.

따라서 0이나 0 아닌 숫자로 표현 가능한 모든 자료형이나 연산식은 모두 논리값을 가질 수 있습니다. 실수의 논리값을 보여주는 간단한 예제를 다음과 같이 만들어 컴파일해보기 바랍니다.

아래 예제를 컴파일 해보면 (1)번과 (5)번은 if의 조건식이 0이므로 false로 출력합니다. 나머지 (2), (3), (4) 번은 1과 1.5, 1의 값을 조건식에 넣은 것이므로 true로 출력됩니다. 즉 실수 자체나 실수를 이용한 연산식이 모두 논리값으로 사용된다는 것을 알 수 있습니다.

#include <stdio.h>


void main(void)
{
float a=0, b=1, c=1.5 ;

if(a) printf("(1) a is true(%f) \n",a);
else printf("(1) a is false(%f) \n",a);

if(b) printf("(2) b is true(%f) \n",b);
else printf("(2) b is false(%f) \n",b);

if(c) printf("(3) c is true(%f) \n",c);
else printf("(c) c is false(%f) \n",c);

if(c-0.5) printf("(4) c-0.5 is true(%f) \n",c-0.5);
else printf("(4) c-0.5 is false(%f) \n",c-0.5);

if(c-1.5) printf("(5) c-1.5 is true(%f) \n",c-1.5);
else printf("(5) c-1.5 is false(%f) \n",c-1.5);
}

23.2.10. main() 함수를 미리 선언할 수 없는 이유


[질문] main()이라는 함수를 #include <stdio.h> 를 이용해 함수를 선언했잖아요. 그런데 '왜?' void main(void)라고 적어주어야 하죠. 이미 선언을 했으니 안 적어줘도 되는거 아닌가요?

[답변]
main() 함수는 stdio.h를 통해서 선언되지 않습니다. main()함수는 C언어에서 반드시 있어야 하는 함수이면서 미리 선언되지 않는 함수입니다. 또한 함수의 형(자료형)도 정해지지 않은 함수입니다. 이는 main() 함수가 지닌 특수성과 중요성을 생각해보면 당연하겠죠. main() 함수의 자료형이나 되돌림값이 특정 형태로 미리 정해진다면 main() 함수의 융통성이 사라지게 됩니다. 때문에 main() 함수는 본체를 정의하면서 함수형도 함께 정의해주는 것입니다.

main() 함수를 일반 함수처럼 다음과 같이 사용한다면 물론 미리 선언한 내용으로 충분합니다.

main();

그렇지만 main() 함수를 이처럼 달랑 함수 이름만 사용하는 경우는 없죠. main() 함수 자체가 프로그램의 본체인데 그 본체의 내용을 정의하지 않은 상태에서 main();라고 사용할 수는 없으니까요. 그래서 main() 함수는 다른 함수와는 달리 소스 전체에 딱 한 번만 등장하며 등장과 동시에 함수형, 함수 선언, 정의, 본체 내용 정의까지 한 번에 끝내는 것입니다.

이와는 달리 사용자 정의함수인 kim() 함수는 소스 파일 곳곳에서 여러 번 사용할 수 있죠. printf() 함수처럼요. 다른 모든 함수는 여러 번 사용 가능하지만 main() 함수는 소스 파일에서 단 한 번만 사용할 수 있다는 점이 특징입니다. 그래서 미리 선언이 불가능한 것이죠. 이런 이유로 main() 함수를 사용할 때마다 함수형과 되돌림값의 형태를 정의해주는 것입니다.

23.2.11.0을 돌려줄 거라면 return 0; 대신 void kim(void)를 써도 되는 것 아닌가요?


[질문] 함수형으로 int 형을 선언하고 되돌림값으로 정수형 숫자인 0을 돌려주는 거라면 굳이 int main(void) { ~~~~~ return 0;} 쓸거 없이 그냥 void main(void) { ~~~ }으로 하면 안되나요?

[답변]
0을 돌려주는 것과 되돌림값이 없는 것은 다릅니다. 정답이 0이라는 말과 정답이 없습니다라는 말은 엄청난 차이가 있는 것입니다.

컴퓨터나 C언어에서 0은 false를 뜻하므로 0의 의미는 매우 중요합니다. 반면 없다는 것은 null을 뜻합니다. 따라서 둘의 의미나 역할은 엄청난 차이를 보입니다.

둘의 차이는 컴퓨터에 대한 기본적인 원리를 알아야 명쾌하게 이해가 됩니다. 컴퓨터의 기본적인 원리를 이해하고자 한다면 제가 쓴 [컴국지]라는 책을 참고하기 바랍니다. null과 0의 차이를 알 수 있습니다.

return 0; 은 0이라는 되돌림값을 돌려준다는 것이므로 계산이 가능한 숫자를 돌려주는 것입니다. 논리값으로 따지면 0이 false가 되므로 '거짓(false)'이라는 중요한 값을 돌려주는 셈입니다.

그렇지만 void형으로 선언하여 되돌림값이 없을 경우에는 아무 것도 돌려주지 않으므로 거짓인지 아닌지 여부를 알려줄 수 없는 것입니다. 그러므로 0을 돌려주는 것과 아무 것도 돌려주지 않은 것은 다릅니다. 이 때문에 int func() {return 0;}과 void func(){} 함수는 전혀 다른 의미를 가집니다.

23.2.12.int main(void)과 void main(void) 중 아무 거나 써도 상관 없나요?


[질문] 책을 중간만 읽은 상태에서 질문합니다. 제가 교재로 사용하는 책에서는 대부분 int main(void) 로 시작하거든요. 근데 [C언어 이야기]에선 예제들이 거의 void main(void) 로 시작되네요. 둘 다 써도 상관이 없나요? 아니면 프로그램 종류에 따라 다르게 쓰는 건가요?

[답변]
책의 뒷 부분에 가면 자료형에 대한 이야기와 함수의 자료형, 되돌림값, 선언에 관한 내용이 나옵니다. 이 부분까지 읽으면 void형과 int형 함수의 차이를 알 수 있습니다.

함수 앞에 사용하는 int, void는 함수의 자료형을 나타냅니다. 괄호 안에 나타내는 자료형은 함수에서 사용하는 매개변수의 자료형을 나타냅니다. 함수의 자료형은 함수의 실행 결과 돌려받는 결과값이 무엇이냐에 따라서 달라집니다. 예를 들어 함수의 매개변수로 정수형을 사용하고, 실행 결과로 문자 상수를 돌려받아야 하는 함수라면 char main(int)로 선언해야 합니다. 실수형 매개변수를 사용하고 실수형 자료로 돌려받아야 하는 함수라면 float main(float)로 선언해야 합니다.

책의 중간에 보면 jegob() 함수가 나오는데 이 함수는 매개변수로 정수형을 사용하고 결과값으로 정수형을 돌려받습니다. 그래서 int jegob(int a, int b)라고 선언했습니다.

따라서 main() 함수 역시 돌려받아야 할 결과값이 있다면 결과값의 자료형에 맞게 선언해주어야 합니다. 따라서 int main(), void main(), char main(), float main() 등으로 다양하게 선언할 수 있으며 이에 따라 main() 함수의 성격은 달라집니다.

제 책에서 사용한 main() 함수는 대부분 되돌림값을 사용하지 않는 예제입니다. 그래서 void형으로 main() 함수를 선언한 것입니다. int형 되돌림값을 이용해야 하는 예제에서는 저도 main() 함수의 자료형으로 int를 사용합니다.

23.2.13. main() 함수의 되돌림값은 어디에 돌려주나요?


[질문] kim() 함수의 되돌림값은 kim() 함수를 호출한 main() 함수에 돌려주잖아요. 그런데 main() 함수에서 되돌림값을 사용한다면 어디에 돌려주나요? main() 함수가 최상위 함수라 main() 함수로부터 돌려받은 되돌림값을 사용할 함수가 없는 것 아닌가요?

[답변]
main() 함수도 되돌림값을 사용합니다. 그리고 main() 함수로부터 돌려받은 되돌림값은 운영체제(즉 도스나 윈도)가 사용합니다. 다음의 소스 파일을 copystr.c라는 이름으로 저장한 뒤에 컴파일해서 도스에서 실행시켜 보기 바랍니다. 터보C나 BC를 이용해 도스용 프로그램으로 만들어 실행시켜야 합니다.

#include <stdio.h>
int main(int argc, char *argv[]) /* 도스 명령어의 매개변수를 입력받는 함수 */
{
int c;
if (argc < 2) /* 명령어만 치고 매개변수를 입력하지 않으면 */
{ /* 사용법을 보여주라는 글을 보여줍니다 */
printf("\n Copy String v 1.0 ");
printf("\n Usage : COPYSTR [String] \n");
return 0;
}
for (c = 1;c < argc;c++)
printf("%s ",argv[c]); /* argv의 배열 요소를 하나씩 화면으로 보여줍니다 */
return 0;
}

위의 소스 파일을 컴파일하면 copystr.exe가 만들어집니다. 이 파일은 매개변수를 입력받아서 다시 화면에 보여주는 프로그램입니다.

그러니까 도스에서 'copystr'이라고만 파일 이름을 입력하면 'Copy String v 1.0'과 다음 줄의 'Usage : COPYSTR [String] ' 문장을 보여줍니다.

그리고 'copystr this is test'라고 입력하면 'this is test'라는 문장을 보여주는 프로그램입니다.

따라서 kim()함수를 main() 함수에서 호출해 사용한 것처럼 main() 함수는 운영체제에서 호출하여 사용합니다. 때문에 main() 함수의 되돌림값은 운영체제에게 넘겨주는 것입니다. 이는 모든 프로그램이 마찬가지입니다.

윈도의 도스창을 여는 명령어인 commmand.com과 exit라는 복귀 명령어가 이를 이용하는 것입니다. 윈도가 command.com이라는 파일을 호출하는 것이죠.

kim() 함수가 되돌림값이 없다는 것을 kim() 함수를 호출한 main() 함수에게 알려주는 것처럼 main() 함수 역시 되돌림값이 없다는 것을 운영체제에게 알려주어야 합니다.

copystr.c에서는 main() 함수의 함수형으로 int 형을 선언했고, 인수로는 정수형과 문자형 인수를 사용했습니다. 그리고 함수형으로 int 형을 선언했기 때문에 되돌림값으로 정수형 숫자인 0을 돌려주었습니다.

이처럼 우리가 사용하는 프로그램(실행 파일)은 운영체제가 호출하는 일종의 작은 함수에 해당합니다. 때문에 실행 파일의 메인 함수인 main() 함수 역시 자료형과 되돌림값을 가져야 하는 것입니다. main() 함수, 다시 말해 실행 파일 자체는 운영체제에서 호출하는 함수가 되는 겁니다. 따라서 main() 함수의 상위 함수는 운영체제가 됩니다.

23.2.14. printf()함수에서 왼쪽 정렬과 오른쪽 정렬의 개념과 기준


[질문] printf() 함수 설명의 정렬 방법에 대해 잘 모르겠습니다. 무엇을 기준으로 정렬한다는 것인지 설명을 부탁합니다.

[답변]
정렬이란 이름 그대로 줄을 정렬시킨다는 뜻입니다. 일상생활에서도 정렬이라는 말을 자주 쓰죠. 군대나 학교에서 '좌로 정렬'이라는 명령을 내리면 왼쪽 사람을 기준으로 맞추고, 우로 정렬하면 우측 사람을 기준으로 맞춥니다. '반장을 기준으로 정렬'이라는 명령을 내리면 반장을 중심으로 줄을 서야하죠.

컴퓨터에서도 마찬가지입니다. 워드프로세서에서도 문단 정렬 기능이 있습니다. 왼쪽 정렬은 문단의 왼쪽을 기준으로 왼쪽부터 차례대로 오른쪽으로 글자를 나열하면서 줄을 맞추는 것이고 오른쪽 정렬은 반대로 오른쪽부터 왼쪽으로 글자를 나열하면 줄을 맞춥니다. 가운데 정렬은 가운데부터 좌우로 글자를 맞추면서 정렬하죠. 이때 다음과 같은 문장을 왼쪽 정렬, 가운데 정렬, 오른쪽 정렬로 정렬(위치시키면)하면 다음과 같이 됩니다.

s시작위치 m중간 위치 e끝 위치
(0) 원래의 문장: 우리나라는 좋은 나라입니다.

(1) 왼쪽 정렬 : 우리나라는 좋은 나라입니다.
(2) 오른쪽 정렬: 우리나라는 좋은 나라입니다.
(3) 가운데 정렬: 우리나라는 좋은 나라입니다.



C언어에서도 정렬의 개념은 같습니다.

'This is %d'라는 문장이 있다고 합시다. 이때 &d는 변수인데, 그 숫자는 12345라고 합시다. 정상적인 경우 'This is 12345'라고 표시되어야 합니다.

그런데 숫자를 입력할 칸으로 10칸을 지정했을 경우에는 'This is 12345*****'로 표시됩니다.

(*표로 표시한 부분은 빈 칸(Space)입니다. 칸의 숫자를 알기 쉽게 하려고 별표로 표시한 것입니다.)

이때 12345라는 숫자는 'This is '에 바로 이어서 출력됩니다. 즉 10칸 중 제일 첫 번째 칸을 기준으로 12345가 출력되고 뒤의 다섯 칸은 빈 칸으로 나타납니다. 이렇게 문장을 보여주는 정렬방식이 왼쪽 정렬 방식입니다. 즉 10칸의 왼쪽 1번 칸을 기준으로 숫자를 적어주는 방식입니다.

오른쪽 정렬은 10칸 중 제일 오른쪽 칸부터 왼쪽으로 글자를 적는 방식입니다. 따라서 'This is *****12345'로 표시됩니다. 즉 10칸의 맨 오른쪽 칸을 기준으로 숫자를 적는 방식입니다.

C언어에서는 아무런 옵션을 주지 않으면 기본적으로 오른쪽 정렬을 해서 문장을 보여줍니다. 예를 들어 다음과 같은 세 가지 명령문을 봅시다.

#include <stdio.h>

main()
{
printf("Num=%f\n",12.3);
printf("Num=%20f\n",12.3);
printf("Num=%-20f\n",12.3);
}

결과는 다음과 같습니다.

Num=12.300000
Num=***********12.300000
Num=12.300000***********

(다시 말하지만 *표는 실제로 빈 칸으로 보이는 부분입니다.)

2번째 명령문은 %20f 명령문을 사용했습니다. %f는 실수를 보여주라는 옵션이고 20이라는 숫자는 20자리까지 표시하라는 명령입니다. 그런데 터보C는 기본적으로 오른쪽 정렬을 해주기 때문에 오른쪽부터 12.300000을 적고 왼쪽의 11칸을 빈 칸으로 둡니다. 12.3이 아닌 12.300000으로 표시되는 이유는 제 책에서 설명했습니다.(아무런 옵션을 안 주면 컴파일러가 알아서 소수점 몇 째 자리까지 표시하라고 지정하고 컴파일하기 때문입니다.)

그리고 3번은 2번의 %20f에 - 기호를 덧붙여 %-20f로 옵션을 주었습니다. - 기호는 왼쪽 정렬을 하라는 옵션입니다. 때문에 왼쪽부터 12.300000을 적고 남은 11자리를 빈칸으로 채웁니다.

그럼 %f로 아무런 옵션을 안 준 1번은 어떻게 된 경우일까요? 1번 명령문은 아무런 옵션을 안 주었기 때문에 기본적으로 오른쪽 정렬입니다. 그런데 몇 칸 까지 표시하라는 옵션도 없죠. 따라서 'Num=' 문장 뒤로 몇 번째 칸부터 오른쪽 정렬을 할 지 모릅니다. 따라서 정렬 자체가 불가능하죠. 이럴 경우 오른쪽 정렬의 위치는 0이 됩니다. 따라서 'Num=' 문장 바로 뒤에 붙어서 나오는 것입니다.

한 가지 주의할 점은 실제로 위의 예문을 컴파일해보면 보기1과 보기3이 같은 모습으로 보입니다. 빈칸은 사람 눈에 안보이니까요. 하지만 1번은 오른쪽에 빈칸이 없는 상태이고, 3번은 오른쪽에 빈 칸이 있는 상태입니다.

그 차이를 확인해보기 위하여 다음과 같이 예제를 고쳐서 컴파일해보기 바랍니다. 숫자를 표시한 다음에 end라는 글자를 덧붙이도록 고쳤습니다.

#include <stdio.h>

main()
{
printf("Num=%f end\n",12.3);
printf("Num=%20f end\n",12.3);
printf("Num=%-20f end\n",12.3);
}

결과는 다음과 같이 나오겠죠.

Num=12.300000 end
Num=***********12.300000 end
Num=12.300000*********** end

이제 오른쪽 정렬 왼쪽 정렬에 대해서 이해가 되시죠?

23.2.15.printf()문의 정렬 방법과 결과의 불일치 문제


[질문] printf() 함수를 이용해 화면에 출력되는 숫자를 정렬해보면 명령대로 정렬하지 않고 엉뚱하게 표시됩니다. 값도 틀리고요. 왜 그럴까요?

[답변]
컴퓨터 언어를 사용할 때는 연산 순서를 잘 이해하고 있어야 합니다. 그래서 여러 사람의 프로그래머가 프로그램을 짜서 똑 같은 계산 결과를 얻더라도 그 결과를 얻기까지의 시간은 프로그램 내용에 따라서 각기 다른 겁니다.

질문한 내용은 무엇부터 처리하느냐의 차이 때문에 발생합니다. 질문의 내용은 계산을 먼저 하느냐 화면표시부터 먼저 하느냐의 차이에서 발생합니다. 무엇부터 먼저 하겠습니까? 당연히 계산부터 먼저 하겠죠. 계산을 마쳐야 화면에 표시를 하던 말던 할테니까요. 따라서 계산을 먼저 한 뒤에 화면에 표시한다는 사실만 기억하면 질문에 대한 해답을 얻을 수 있습니다.

다음의 예제를 보죠.

printf("this is %10.1f/n".123.456);

먼저 10.1f에서 .1f에 의하여 123.456은 소수 첫째 자리까지만 남습니다. 이때 123.4가 남는 것이 아닙니다. 즉 소수 첫째 자리까지만 남길 때는 무 자르는 것처럼 123.4와 56의 두 부분으로 잘라내는 것이 아니고 맨 뒷자리부터 연산해서 잘라냅니다. 그래서 6을 먼저 잘라내고 5를 잘라냅니다. 이 과정에서 반올림을 해주기 때문에 123.4가 아니라 123.5로 반올림 된 수가 남습니다.

이제 이렇게 계산된 123.5를 10칸에 맞추어 오른쪽 정렬을 합니다. 그래서 아래처럼 10칸 중에서 오른쪽 다섯 칸에 123.5가 표시되고 왼쪽에는 공백문자(빈 칸)가 표시됩니다. (제가 별표로 표시한 부분이 공백문자 부분이죠.)

*****123.5

2. 이번에는 다음의 예제를 보죠.

printf("this is %5.5/n".123.456);

먼저 계산을 먼저 하면 소수점 다섯 자리까지 계산하므로 123.45600 이 나오죠. 9자리로 된 결과가 나왔습니다. 이제 이렇게 계산된 내용을 화면에 표시해봅시다.

다섯 칸 안에 메꾸어 넣으려면 네 자리는 잘려야 합니다. 이때 오른쪽 정렬이니까 오른쪽부터 다섯 글자를 차례대로 왼쪽으로 밀어넣는다면 다음과 같이 표시되어야 합니다.

45600

완전히 엉뚱한 답이 되는 셈이죠.

그리고 왼쪽부터 밀어넣고 오른쪽을 끊을 경우에도 문제는 발생합니다.

123.4라고 적을 경우 원래 우리가 의도했던 소수점 다섯 자리 부분의 수는 볼 수 없는 셈이죠.

즉 어떻게 자르더라도 계산 결과와는 아주 다른 엉뚱한 답이 화면에 표시됩니다. 그래서 이런 경우 우선 답을 충실하게 보여주는 방향으로 화면에 표시합니다. 그래서 다섯 칸에 보여달라고 옵션을 주었지만 123.45600이라는 정확한 계산 값을 보여주는 것입니다. 45600을 보여줄 수는 없기 때문입니다.

이처럼 컴파일러에서 결과물을 처리할 때 어떤 원리와 규칙에 의하여 처리하느냐에 따라서 화면에 표시되는 내용이 모두 달라집니다. 프로그래머는 이런 점을 모두 고려해서 프로그램을 짜야겠죠.

똑 같은 123.456을 가지고 다루지만 계산 순서와 화면 표시방법에 따라서 123.5, 123.46, 123.45600으로 각기 다르게 화면에 출력될 수 있는 이유는 이 때문입니다.

따라서 이런 차이점을 평상시 알고 있어야 오차가 없는 정확한 계산이 가능해집니다.

23.2.16. <>와 "" 기호의 차이


[질문] #include 명령으로 헤더 파일을 지정할 때 어떤 경우에는 <> 기호를 이용하고 어떤 경우에는 "" 기호로 감싸는데 두 기호의 차이는 무엇인가요?

[답변]
제 책의 본문에서 설명한 내용이지만 다시 한 번 말씀 드리겠습니다.
헤더 파일을 만들 때 꼭 지켜야할 원칙은 아니지만 묵시적으로 지키는 규칙이 있습니다. <>와 ""의 구분법입니다. 그 동안 제 책을 통해서 살펴본 것처럼 어떤 경우에는 #include 라고 적고 어떤 경우에는 #include "kim1.h"라고 헤더 파일을 감싸는 기호가 달랐습니다.

둘은 어떤 차이가 있을까요? 없습니다. 둘 다 헤더 파일을 포함시킬 때 사용하는 기호입니다. 그렇지만 묵시적으로 <> 기호는 컴파일러에서 기본적으로 제공하는 헤더 파일을 포함시킬 때 사용하고, "" 기호는 사용자 정의 헤더 파일을 포함시킬 때 사용합니다.

이렇게 사용하는 이유는 두 기호의 기능적인 차이 때문입니다.

<> 기호로 묶인 헤더 파일의 경우 경로 중에서 디렉토리 부분이 생략되고 파일 이름만 적혀있을 경우(대개의 파일 이름만 적습니다) 헤더 파일을 컴파일러가 설치된 디렉토리에서부터 찾습니다. 또는 컴파일러의 환경설정을 통해서 설정한 헤더 파일 디렉토리부터 찾습니다. 컴파일러가 설치된 디렉토리에는 컴파일러에서 제공하는 기본적인 헤더 파일이 들어있기 때문에 <> 기호로 묶인 헤더 파일은 컴파일러의 기본 헤더 파일을 가리킬 때 사용합니다.

반면 "" 기호로 묶인 헤더 파일을 찾을 때는 현재 디렉토리에서부터 찾습니다. 그 다음에 컴파일러 프로그램에서 지정한 디렉토리를 검색합니다. 현재 디렉토리에는 대부분 사용자가 만든 헤더 파일이 들어있기 마련이죠. 그래서 "" 기호로 묶인 헤더 파일은 사용자 정의 헤더 파일을 가리킬 때 사용합니다.

이제 <> 기호와 "" 기호의 기능적인 차이를 알 수 있습니다. 그렇지만 오늘날에는 두 기호의 차이를 경로 검색의 차이로 이해하기보다는 헤더 파일 제작자를 구분하는 용도로 더 많이 사용하고 있습니다.

이처럼 컴파일러에서 제공하는 기본적인 헤더 파일과 사용자 정의 헤더 파일을 나타내는 기호를 달리 하는 이유는 쉽게 알 수 있습니다. 소스 파일을 분석하는 사람들을 위한 배려입니다. 물론 프로그래머 자신도 헤더 파일의 분석을 쉽게 하기 위한 의도가 있습니다.

만약 모든 헤더 파일을 <> 기호로만 묶는다고 합시다. 이럴 경우 다음과 같이 사용합니다.

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

이중 hanio.h 와 basicio.h 라는 헤더 파일은 터보C 컴파일러에서 제공하는 헤더 파일이 아닙니다. 그렇지만 소스 파일만 봐서는 어느 것이 컴파일러에서 제공하는 헤더 파일이고 어느 것이 사용자 정의 헤더 파일인지 구분할 수 없습니다. 이 경우 제 3의 프로그래머가 이 소스 파일을 컴파일해보면 hanio.h 와 basicio.h 라는 헤더 파일이 없어서 오류가 발생합니다. 이럴 경우 고급 사용자가 아닌 초보 사용자의 경우에는 hanio.h 와 basicio.h 라는 헤더 파일이 "왜 없을까? 어디 있을까?"로 고민하게 됩니다. 자신의 컴파일러 프로그램에 문제가 있는 것이 아닐까 하는 의심도 듭니다.

그렇지만 아래와 같이 사용자 정의 헤더 파일을 ""로 묶어서 표현해봅시다.

#include <stdio.h>
#include
#include "hanio.h"
#include "basicio.h"

이런 경우에는 이중 hanio.h 와 basicio.h 라는 헤더 파일이 컴파일러에서 제공하는 헤더 파일이 아니라는 것을 한 눈에 알 수 있습니다. 소스 파일의 제작자가 만들어 사용한 헤더 파일이라는 사실을 한 눈에 파악할 수 있기 때문에 자신의 컴파일러 프로그램에서 기본적으로 제공하는 파일 중에 hanio.h 와 basicio.h 라는 헤더 파일이 없다는 사실을 바로 인지할 수 있죠.

이런 이유로 컴파일러에서 제공하는 기본적인 헤더 파일은 <> 기호로 묶고 사용자 정의 헤더 파일은 "" 기호로 묶습니다. 물론 둘의 차이를 상관하지 않고 사용자 정의 파일을 <> 기호로 묶어도 상관 없습니다. 반대로 컴파일러의 기본 헤더 파일을 "" 기호로 묶어도 상관 없습니다. 경로만 제대로 지정이 된다면 말입니다.

그렇지만 관습에 따라서 사용자 정의 헤더 파일을 "" 기호로 묶습니다. 여러분도 자신이 만든 헤더 파일을 삽입할 때는 가능한 "" 기호를 사용하기 바랍니다.

23.2.17.include 와 scanf() 생략할 경우의 현상


[질문] "해당 구성요소 가운데 일부를 삭제하게 된다면, 어떤 결과가 나올까"하는 의문을 가지고 #include와 scanf("%d",&a);를 생략하고 프로그램을 작성해 보았습니다. 그리고 컴파일러를 실행해 보았는 데, compile to OBJ에서는 "warning"이라는 메시지오 함께 Possible use of 'a' before definition in function main이란 메시지가 나왔습니다. "error"란 메시지를 예상했는 데, "warning"이 나왔더군요. 그래서 다시 Make EXE file를 실행했는 데 이 부분에선 "success"란 메시지가 나왔습니다. 결국 #include와 scanf("%d",&a);이 없어도 실행이 되었습니다. 그리고 도스상태에서 형성된 파일을 실행해 보니 다음과 같은 결과가 화면에 출력되었습니다.

INput Number : Input number=252
input*input=-2032

의문점은 아무런 숫자를 입력하지도 않았는 데 해당 파일을 실행하면 252라는 숫자가 스스로 입력되면서 -2032를 출혁했다는 점입니다. 이와 같은 출력결과와 scanf("%d",&a); 생략 사이에는 과연 어떤 관계가 있는지요? 사용자로부터 숫자(정수)를 입력받아서 "a"라는 변수에 넣으라는 의미를 지닌 scanf("%d",&a);가 생략되었음에도 "252"라는 숫자가 스스로 생성되면서 "-2032"라는 결과가 나온 점이 무척 궁금합니다.

또한, #include에 대한 설명이 나와있지만, 좀 더 구체적인 설명이 있었으면 좋겠습니다. #include를 생략해도 파일은 정상적으로 실행되는 데, 도대체 #include은 어떤 역할을 하는지요? 궁금합니다.

[답변]
질문하신 내용에 대한 해답은 책을 읽으면 볼 수 있습니다. 책 뒤 편에 #include문과 변수 선언이 안되었을 때의 결과에 대해서 설명 해놓았습니다. 책에 있는 내용이므로 간단하게 답변을 드리겠습니다.

1. scanf() 함수를 생략했는데 어떻게 값이 대입되는가

변수를 선언할 때나 또는 선언한 후에 사용자가 값을 직접 지정하지 않을 경우 프로그램이 알아서 아무 값이나 일단 넣습니다. 사용자가 원하지 않는 값이며 어떤 값이 대입될지 모르기 때문에 일명 쓰레기값이라고 부릅니다. 따라서 변수는 선언하는 순간 어떤 값이 대입됩니다. 따라서 scanf() 함수를 사용하지 않았지만 변수 a에는 어떤 값이 들어있는 셈입니다. 다만 그 값은 컴퓨터가 알아서 정합니다. 컴퓨터 사용환경에 따라서 매번 값이 달라질 수 있다는 뜻입니다.

그리고 쓰레기값이 대입되다보니 결과값 역시 예상 밖의 수치가 나오는 것입니다. 두 수를 곱했는데 -2032라는 수가 나오는 까닭은 두 수를 곱한 결과가 정수형 변수의 저장범위를 넘어섰기 때문입니다. 그러니까 정상적으로 짠 프로그램이더라 하더라도 변수에 저장할 수 있는 범위의 숫자가 나올 경우 음수로 표시됩니다. 뒷부분에 나오는 자료형에 관한 자료를 참고하시면 이 부분에 대한 좀더 자세한 해답을 얻을 수 있습니다.

2. include 를 생략해도 되는가?

#include 문의 용도에 대해서는 책 본문에 설명한 내용을 참고하기 바랍니다. #include <stdio.h> 명령을 주는데 stdio.h 파일에는 printf() scanf() 등의 함수 선언문이 들어있습니다.

함수 선언문을 생략할 경우 경고는 발생하지만 실행에는 지장이 없습니다. 함수선언문이 생략될 경우에도 컴퓨터는(그러니까 실제로는 컴파일러가 프로그램을 컴파일할 때) 자기가 알아서 함수의 자료형을 결정합니다. 때문에 엉뚱한 결과값이 나올 수는 있어도 일단 컴파일하고 실행하는 일은 해줍니다.

23.2.18. for 문에서 명령 실행 순서


[질문] 아래의 예제를 만들었습니다.

#include <stdio.h>
void main(void)
{
int a;
for(a=1;a<=4;a++)
{
if (a%2==0)
printf("숫자 %d 는 짝수다.",a);
if (a%2==1)
printf("숫자 %d 는 홀수다.",a);
}
}

여기서 For문에 명령문 부분이 a++이라거 되어 있는데 a를 1로 선언했으니까 a++때문에 2가 되서 if문에 2로 대입되어야 하는데, 아니더라구여

실행하니까

숫자 1 는 홀수다
숫자 2 는 짝수다
숫자 3 는 홀수다
숫자 4 는 짝수다

이렇게 나오더라구여 왜 첨에 2로 대입이 안되고 1로 대입이 되었는지 알고 시퍼요..ㅡ.ㅜ

[답변]
for문의 동작 순서 때문에 혼동하신 것 같군요. for문의 경우 먼저 변수 대입문이 동작합니다. 이어서 조건문이 실행되죠. 그리고 조건문의 조건에 따라서 명령 실행문이 실행됩니다. 이때 별도의 함수가 없다면 세 번째 부분의 명령문이 바로 실행되지만 별도의 실행문이 존재한다면 먼저 실행문을 실행시킵니다. 그런 다음에 제일 마지막으로 for 문 안의 명령 실행문이 실행됩니다. 순서를 따지면 다음의 순서입니다.

[보기1] 별도의 실행문이 없을 때의 실행순서

for(1대입문; 2조건문; 3명령실행문);

[보기2] 별도의 실행문이나 함수가 붙었을 때

for(1대입문; 2조건문; 4명령실행문)
{3명령 실행문}

예제소스에서 a++은 for 문 다음의 실행문인 {} 안의 실행문이 먼저 실행된 다음에 실행됩니다. 따라서 먼저 {} 안의 짝수 홀수 출력문이 출력된 뒤에야, a++ 이 실행되는 것이죠.

제어문은 조건에 따라서 명령을 수행하는 순서가 조금씩 차이 납니다. do while문과 while문의 수행 순서 차이는 대표적인 경우죠. 명령 실행 순서에 대한 설명은 [C언어 이야기] 본문에 수록되어 있으니 책을 참고하기 바랍니다.

23.2.19.문자열을 저장하는 방법에는 어떤 것이 있는지 궁금합니다


[질문] 문자열을 저장하는 방법에는 어떤 것이 있는지 궁금합니다

[답변]
문자열을 저장하려면 그냥 문자열관련 함수를 이용해도 되고, 문자열 포인터를 이용해도 됩니다. 또는 배열을 이용해도 됩니다.(배열이 곧 문자열 포인터입니다.)

'char *src'와 같이 선언하는 기본적인 문자열 포인터 사용법을 이용하면 문자열은 손쉽게 다룰 수 있습니다. 복잡하게 고민할 필요 없이 기본적인 문자열 포인터 사용법을 이용하여 다루기 바랍니다.

23.2.20.배열에 저장된 값을 역순(거꾸로)으로 출력하는 방법


[질문] 배열 출력할때 A[0]~A[N]에 저장된값을 꺼꾸로 출력 하려면 어떻게...하죠?

[답변]
배열의 순서를 거꾸로 출력하고자 할 때는 배열의 뒷 부분부터 거꾸로 앞으로 가면서 출력하면 됩니다. 즉 ar[9] ar[8] ar[7]... 순으로 출력하면 되겠죠. 이때 n을 9라고 할 때 ar[n] ar[n-1] ar[n-2]... 와 같은 순서로 출력하면 됩니다.
이때 출력해야 할 배열이 많다면 일일이 [n-2] [n-m]... 의 형태로 프로그램에 써 줄 수 없죠. 이때는 [n-i]의 형태로 한 번만 써주고 for문을 돌려 i의 값을 연산자로 하나씩 증감하는 방법을 사용하면 됩니다.

for(i=0;i
보기와 같이 하면 배열 순서를 거꾸로 하여 출력할 수 있습니다.

23.2.21.입력받은 변수의 숫자로 배열의 크기를 선언하는 것이 가능한가요?


[질문] 배열의 크기를 소스 파일에서 지정하지 않고 scanf로 입력받은 다음에 배열을 선언하려고 하는데 잘 안되네요. 즉 소스 파일에 int mm[n]으로 적고 scanf()로 n의 값을 5를 입력받으면 될 것 같은데 잘 안되네요. 그러면 int mn[5]가 될 것 같은데 이처럼 배열의 크기를 선언하는 것이 가능한가요?

[답변]
요즘의 언어는 배열을 선언할 때 변수를 이용할 수 있지만 초기의 C언어는 변수를 선언할 때 변수를 이용할 수 없습니다. 따라서 int anum[n]과 같이 배열 선언에 n이라는 변수를 사용할 수 없습니다. 그러므로 scanf로 5를 입력받아 n이라는 변수의 값을 5로 정하고 이를 int anum[5] 명령으로 대치하고 싶지만 이것은 안 되는 방법입니다.
이 점은 초기 C언어의 단점입니다. 그래서 당시에는 나중에 사용할 배열 크기를 모를 때 충분한 크기의 배열을 미리 잡아서 사용하는 방법을 썼습니다. 즉 입력받을 배열 크기가 1~50 사이라면 애초 배열의 크기를 50으로 선언하는 방법을 쓴 것입니다.
그렇지만 이 방법은 조금 비효율적인 방법입니다. 메모리를 많이 잡아먹는 방법이죠. 그래서 가변적인 배열을 사용할 때는 배열의 크기를 지정하지 않고 배열을 선언하거나 포인터를 이용합니다.

23.2.22.크기를 모르는 배열을 지정하는 방법과 배열 수만큼 %d를 사용하는 방법


[질문] 배열의 크기를 모르는 경우가 있죠. 예를 들어 대입받은 변수의 크기만큼 배열 크기를 선언하고 여기에 값을 지정해야 하는 경우요. 그런데 int a[n]이라고 지정할 수 없잖아요. 이처럼 크기를 모르는 배열은 어떻게 지정할 수 있나요? 그리고 이 배열을 출력하기 위해서는 %d를 printf() 함수에 사용해야 하는데 배열 크기만큼 %d를 함수 안의 문장에 사용할 수 없잖아요. 또 배열 크기도 모르고. 이런 경우 어떻게 크기를 모르는 배열에 저장된 값을 출력할 수 있나요?

[답변]
1. 배열의 크기가 확정되지 않아서 배열의 크기를 모를 때 사용하는 방법은 대략 세 가지입니다. 첫 번째는 배열의 크기를 정하지 않는 것입니다. 즉 ar[9]처럼 [] 안에 숫자를 적으면 배열의 크기가 확정되지만 ar[]과 같이 사용하면 배열의 크기가 확정되지 않기 때문에 나중에 필요한 크기의 배열을 집어넣을 수 있습니다.

두 번째는 포인터를 이용해 배열의 첫 번지만 지정하는 방법입니다. 결과적으로 첫 번째 방법과 같은 방법이지만 포인터를 사용한다는 점이 차이점입니다.

세 번째는 배열의 크기를 #define 문을 이용한 상수로 지정한 다음에 #define 문으로 상수의 크기를 바꾸는 방법이 있습니다. 즉 ar[MAX+2]와 같이 지정한 다음에 MAX의 크기를 #define 문으로 바꾸는 방법이 있습니다. 그런데 이 방법은 컴파일할 때 프로그래머가 사용할 수 있는 방법으로 실행 파일을 실행시킨 후에 사용자가 사용할 수 있는 방법은 아니죠.

그외 배열의 크기를 메모리가 허용하는 최대치로 잡아놓고 배열을 사용하는 방법도 있지만 이는 비효율적인(그렇지만 초보자가 사용하기에 가장 편한) 방법이 아니므로 앞서 말한 세 가지 방법을 가장 많이 사용합니다. 그 중에서도 포인터를 이용한 방법이 가장 많이 사용됩니다.

2. printf()함수 안에 수 천 개나 되는 %d를 적어줄 수는 없습니다. 이런 경우 제어문을 이용해 루프를 돌려주어야 합니다. 책에 적힌 for, if, while 등의 순환문에 대한 설명 부분을 참고하기 바랍니다.

3. 아래의 예제를 사용해보기 바랍니다. 배열의 크기를 지정하지 않고도 나중에 0부터 8까지 0개의 배열을 대입시키고, 이를 순서대로 그리고 거꾸로 출력하는 예제입니다. 아래의 예제를 컴파일해보면 질문한 내용에 대한 해답을 모두 얻을 수 있습니다.

#include <stdio.h>
#include
#include

int *ar;
void main(void)
{

int n=0;
for(n=0;n<9;n++) *(ar+n)=n;
for(n=0;n<9;n++) printf(" %d",*(ar+n));
printf("\n Reverse: ");
for(n=8;n>=0;n--) printf("%d ",*(ar+n));
printf(" End pointer\n\n");
getch();

}

23.2.23. ## 기호의 의미


[질문] 다음 예제를 이렇게 생각 해봤는데요.

#include <stdio.h>
#define HAB(n,m) (n##m)
void main(void)
{
int a=10,b=20,ab;
printf("a=%d|n",a);
printf("b=%d|n",b);
printf("ab=%d|n",HAB(a,b));
}

이렇게 생각을 해보았는데..

그러면 값이 내 생각엔 a=10,b=20,ab=1020이 라고 생각을 했는데, 막상 값을 보면 ab=1로 나옵니다.

왜 그런지 좀 가르쳐 주십시요...

[답변]
책에 제가 쓴 내용을 잘 살펴보기 바랍니다.

(n##m)은 두 글자를 하나로 합쳐주는 것에 불과합니다. 그래서 HAB(a,b)라는 함수의 결과는 'ab'가 됩니다. 따라서 printf("ab=%d\n",HAB(a,b)); 는 바꿔 말하면 printf("ab=%d\n",ab); 가 됩니다. 즉 ab라는 변수의 내용을 출력해야 하는 것입니다.

그런데 예제의 첫 줄에서 int a=10,b=20,ab; 로 선언했죠. ab라는 변수에 값을 대입하지 않았습니다. 따라서 ab는 쓰레기값을 현재 가지고 있는 상태입니다. 그래서 엉뚱하게도 1이라는 답이 나온 것입니다.

##은 글자를 붙여주는 역할을 하는 것이지, 글자가 뜻하는 변수의 값을 붙여주는 것이 아닙니다.

a##b는 a의 값과 b의 값을 붙여서 보여주는 것이 아닙니다. a##b는 ab라는 이름으로 만들어줄 뿐입니다. a의 값인 10과 b의 값인 20을 붙여주는 것이 아니라는 뜻입니다. 책 본문의 예제를 다시 읽어보시면 이해가 되실 겁니다.

23.2.24.표준입출력 장치란?


[질문] 표준입출력 장치란 무엇을 말합니까?

[답변]
'표준 입출력'이란 말 그대로 표준이 되는 입출력입니다. 입력이란 어떤 자료를 받아들일 때 사용하는 장치를 말하고 출력은 어떤 내용을 보낼 때 사용합니다.

파일을 하나 복사하는 과정을 생각해봅시다. 윈도의 탐색기나 도스의 copy 명령어로 a.txt 파일을 b.txt로 복사했다면 a.txt 파일의 내용을 입력받아서, 그 내용을 다시 b.txt 파일로 출력한 것이 됩니다. 즉 파일 복사의 경우 a.txt가 입력부, b.txt가 출력부로 설정됩니다.

가장 흔한 경우는 우리가 키보드로 입력받은 내용을 모니터로 출력해주는 것입니다. 이때 글자를 입력받는 키보드는 입력장치이고, 화면에 보여주는 모니터는 출력장치입니다.

컴퓨터의 경우 플로피디스크, 하드디스크, 파일, 디렉토리, 폴더, CD롬드라이브, CD, 키보드, 모니터, 눌, 프린터, 모뎀, 메인보드의 각 부품 등이 모두 파일로 취급됩니다. 이 말은 곧 이들 장치가 모두 입출력장치로 사용될 수 있다는 뜻입니다. 모든 파일은 기본적으로 입출력이 가능하기 때문입니다. 이런 내용은 하드웨어에 관한 지식과 소프트웨어에 관한 지식을 많이 습득하면서 깨칠 수 있습니다. 이런 내용에 관해 단기간에 습득하고 싶다면 제가 쓴 [컴국지]라는 책을 참고하기 바랍니다.

하여간 이런 많은 장치 중에서 표준으로 사용되는 입출력 장치를 표준 입출력 장치라고 합니다. 대개의 경우 키보드를 표준 입력장치로, 모니터를 표준 출력 장치로 설정해 사용합니다. 그러나 파일이나 프린터와 같은 다른 장치를 표준 입출력 장치로 설정할 수도 있습니다. '표준 입출력 헤더 파일'은 곧 이런 표준 입출력 장치를 다루는 함수에 관한 헤더 파일인 셈이죠.

23.3.오류 처리 방법


23.3.1.[Statement missing ;]


[질문] 프로그램을 컴파일할 때 오류가 납니다. 'Statement missing ;'이라는 메시지가 나오는데 무슨 뜻인가요?

[답변]
오류 메시지의 내용이 'Statement missing ;'라고 되어 있죠? 이 말은 문장 중에 ; 가 빠져있다는 뜻입니다. 즉 ; 기호를 빼먹었다는 뜻입니다. 쉽게 말해서 오타가 있다는 뜻입니다.

오류가 났을 때 오류 안내문을 선택하면 소스 파일에서 오류가 난 부분을 표시해줍니다. 이 문장을 잘 보면 문장 맨 마지막에 문장 끝을 나타내는 ; 기호가 빠진 상태라는 것을 알 수 있을 겁니다.

따라서 문장 맨 뒤에 문장 끝 기호인 ; 기호를 추가해주면 오류를 해겨할 수 있습니다.

컴퓨터 언어는 점 하나만 달라져도 오류가 납니다. ;와 :, .과 , 기호는 비슷해보이지만 결과는 완전히 다르게 나타나죠. 점 하나 또는 글자 하나 빼먹는 실수는 부지기수로 하는 실수입니다. 오류가 났을 때는 오류 메시지를 잘 살펴보시면 해답이 나옵니다. 'Statement missing ;'이라는 오류 메시지 속에 이미 원인과 해답이 들어있는 셈이죠.

오류 메시지를 판독하려면 오류 메시지의 뜻과 해결방법을 적은 라이브러리 책을 한 권 따로 구입하시는 것이 좋습니다.

23.3.2.Undefined symbol '1SYMBOL' in module '2MODULE'


[질문] 'undefined symbol _closegraph in module ..\MAKING\VAC.C'와 같은 형식으로 오류 메시지가 표시됩니다. 어떤 오류인가요?

[답변]
질문하신 형태와 같은 오류 메시지는 컴파일 과정에서 발생한 오류가 아니고 링크 과정에서 발생하는 오류입니다. TLINK 프로그램을 사용할 경우 자주 발생합니다.

[Undefined symbol '1SYMBOL' in module '2MODULE']의 의미는 모듈(2MODULE 부분) 안에 심볼(1SYMBOL)이 없다는 뜻입니다. 즉 사용자가 사용한 모듈(=함수)이 오브젝트 파일이나 라이브러리 파일 등에 존재하지 않는다는 뜻입니다.

위의 오류문은 _closegraph라는 심볼을 VAC.C라는 파일에서 발견할 수 없다는 뜻이죠.

그렇다면 어떤 경우에 사용자가 사용한 심볼이 모듈에 포함되지 않을까요? 아래와 같은 경우를 예상할 수 있습니다.

1. 심볼의 이름을 잘못 적은 경우
2. 모듈의 이름을 잘못 적은 경우
3. 오브젝트 파일의 이름을 빼먹은 경우
4. 심볼에 대한 선언이 맞지 않은 경우

위의 오류 메시지는 사용자의 오타 때문에 발생하는 경우가 가장 많습니다. 이럴 경우 이름을 제대로 적었나 다시 한 번 확인해봐야 합니다. 즉 가장 먼저 검사해야 할 부분은 심볼이나 모듈의 이름을 제대로 적었나 확인하는 것입니다.

이름을 제대로 적었다고 생각하는 분이 많은데 다시 한 번 확인해보기 바랍니다. 컴파일러와 링커는 옵션에 따라서 대소문자를 구별하기도 합니다. 대소문자 여부까지 확인해보기 바랍니다.

두 번째로 오브젝트 파일이나 헤더 파일의 이름을 빼먹었나 잘 확인해보기 바랍니다. _closegraph 함수는 그래픽 관련 함수로 그래픽 라이브러리 파일을 링크시켜 컴파일합니다. 따라서 VAC.C라는 파일에 graphic.h 헤더 파일을 포함시켰는지 확인해야겠죠. #include 명령을 삽입했나 확인해봐야 합니다.

만약 소스 파일에 include 명령으로 graphic.h 파일을 포함시켰다면 컴파일러의 환경설정에서 헤더 파일이나 라이브러리 파일의 경로를 제대로 지정했는지 확인해야 합니다. 소스 파일에서 파일 이름을 제대로 지정했다 하더라도 환경설정에서 디렉토리 설정을 잘못 해주면 링크하면서 라이브러리 파일을 포함시키지 않습니다. 그럴 경우 이런 오류가 발생합니다.

4번의 경우는 pascal, cdecl형 등의 선언이 불일치 할 때를 말하는데 극히 드문 경우이고 초보자가 사용하는 함수에서 발생하는 일이 거의 없는 경우이므로 더 이상 설명 드리지 않겠습니다.

대개의 경우 오류나 경고는 사용자의 오타나 환경설정 두 가지 이유가 대부분을 차지합니다. 다시 한 번 소스 파일을 확인하고 환경설정을 확인해보기 바랍니다.

23.3.3.'xxxxx' : undeclared identifier


[질문] 'gotoxy' : undeclared identifier 라는 오류가 나기도 하고, 'sound' : undeclared identifier 라는 오류가 나는 경우가 있습니다.

[답변]
'undeclared identifier'의 뜻은 함수가 정의되지 않았다는 뜻입니다. 따라서 gotoxy라는 함수가 정의되지 않았다는 것을 가리킵니다. 이 말은 곧 gotoxy라는 함수가 컴파일러에서 지원되지 않거나 gotoxy 함수가 선언된 헤더 파일을 포함시키지 않았다는 뜻입니다. 그래서 gotoxy() 함수를 사용할 수 없는 것입니다. 따라서 컴파일러에서 gotoxy() 함수를 지원하는 가부터 살펴봐야 합니다.

'sound' : undeclared identifier 라는 메시지 역시 sound라는 함수의 정체가 정의되지 않았다는 뜻입니다. 다시 말해서 함수가 없다는 뜻입니다.

sound() 함수는 터보C에서는 지원이 되지만 볼랜드C++이나 비주얼C++에는 없는 함수입니다. 따라서 sound() 함수 오류가 발생하는 이유는 터보C용 소스 파일을 볼랜드C++에서 컴파일했기 때문에 발생합니다.

23.3.4.[Function 'printf' should have a prototype]


[질문] 프로그램을 작성한 다음 컴파일하는 도중 "Unable to open include file'STDIO.H'" "Function 'printf' should have a prototype" 이라는 메시지가 뜨면서 오류가 납니다.

[답변]
"Function 'printf' should have a prototype" 이라는 메시지는 'printf() 함수의 프로토타입(원형)'을 가져야 한다는 뜻입니다. 즉 printf() 함수의 원형을 발견하지 못했을 때 나타나는 오류입니다. 이 오류가 나타난다는 말은 곧 printf() 함수의 원형을 가지고 있는 'STDIO.H' 파일이 포함되지 않았기 때문에 나타나는 오류문입니다.

따라서 소스 파일의 앞 부분에 #include 'stdio.h' 라는 명령이 있나 확인해보기 바랍니다. 'stdio.h' 파일이 정상적으로 포함되어 컴파일되면 자동적으로 사라지는 오류 메시지입니다.

23.3.5.[Unable to open include file 'STDIO.H']와 [Function 'printf' should have a prototype]


[질문] 컴파일 도중에 "Unable to open include file'STDIO.H'" "Function 'printf' should have a prototype" 이라는 메시지가 뜨면서 오류가 납니다.

[답변]
오류 메시지의 내용은 'STDIO.H' 파일을 포함하지 못하겠다는 뜻입니다. 이런 메시지는 컴파일할 때 'STDIO.H' 파일을 찾을 수 없을 경우 나타납니다. 그럼 'STDIO.H' 파일을 찾지 못하는 경우는 어떤 경우일까요?

1. 'STDIO.H' 파일이 없는 경우

'STDIO.H' 파일이 사용자의 하드디스크에 없다면 당연히 파일을 찾을 수 없고, 'STDIO.H' 파일을 포함하지 못한다는 오류 메시지가 나타나겠죠.

2. 'STDIO.H' 파일은 있지만 경로지정이 잘못된 경우

'STDIO.H' 파일이 터보C나 볼랜드C++에 포함되어 있다 하더라도 환경설정에서 엉뚱한 디렉토리로 설정했다면 역시 'STDIO.H' 파일을 찾을 수 없습니다. 그러니까 실제로 'STDIO.H' 파일이 있는 곳을 지정하지 않고 'STDIO.H' 파일이 없는 디렉토리를 지정했을 경우에 생깁니다. 따라서 환경설정을 제대로 해주어야 합니다.

'STDIO.H' 파일은 헤더 파일이라는 것입니다. 헤더 파일에 대한 설명은 [C언어 이야기]에 자세하게 설명되어 있으니 책을 참고하기 바랍니다. 헤더 파일의 경로를 지정하려면 다음과 같이 합니다.

(1) 터보C의 경우:

메뉴에서 'Options'을 선택하고, 'Directories'를 선택합니다. 'Include directories' 항목을 선택한 후에 'STDIO.H' 파일이 있는 디렉토리를 지정합니다. 터보C가 제대로 설치되었다면 'C:\TC\INCLUDE'로 설정되는 것이 정상입니다.

그러나 이곳의 설정 내용이 다르거나 또는 설정된 값은 맞는데 'STDIO.H' 파일이 엉뚱한 디렉토리에 들어있을 경우 앞서 말한 오류가 발생합니다. 따라서 'STDIO.H' 파일이 어느 디렉토리에 있나 확인해본 다음에 'STDIO.H' 파일이 있는 디렉토리를 적어주면 됩니다.

디렉토리 설정 메뉴에 관해서는 [C언어 이야기]의 본문을 참고하기 바랍니다.

(2) 볼랜드C++의 경우:

역시 마찬가지로 메뉴에서 'Options'을 선택하고, 'Directories'를 선택합니다. 'Include directories' 항목을 선택한 후에 'STDIO.H' 파일이 있는 디렉토리를 지정합니다. 볼랜드C++이 제대로 설치되었다면 'C:\BORLAND\INCLUDE'로 설정되는 것이 정상입니다.

볼랜드C++의 디렉토리 설정 메뉴에 관해서도 책의 본문을 참고하기 바랍니다.

두 번째 오류문인 "Function 'printf' should have a prototype" 이라는 메세지는 'STDIO.H' 파일이 포함되지 않았기 때문에 나타나는 오류문입니다. 'STDIO.H' 파일이 정상적으로 포함되어 컴파일되면 자동적으로 사라지는 오류 메시지입니다.

23.3.6.[Unable to open include file 'STDIO.H']와 [Unable to creat output file C:\BC31\WORK\TEST.obj]의 관계


[질문] 컴파일이 되지 않고 다음과 같은 오류가 나타납니다..

Unable to open include file 'STDIO.H'
Unable to creat output file C:\BC31\WORK\TEST.obj

[답변]
오류가 난 이유는 stdio.h 파일을 찾지 못하기 때문입니다. 사용하신 도스용 bc3.1이 통합용 프로그램이라면 헤더 파일의 환경설정이 잘못된 경우입니다. 따라서 헤더 파일 디렉토리를 제대로 지정해주면 됩니다.

그리고 Work 디렉토리는 프로그램 실행과 상관 없으며 Output 디렉토리는 님께서 원하는 디렉토리를 적어주시면 됩니다. 물론 비워두어도 상관 없습니다. 비워둘 경우에는 bin 디렉토리에 프로그램이 만들어집니다.

23.3.7.Unable to create output file 'hello.obj'


[질문] [error c:\tc\hello.c :Unable to create output file 'c:tc20\workshop\hello.obj]라는 오류 메시지가 나타납니다.

[답변]
오류 메시지를 보니 다음이 원인입니다. TC의 output 디렉토리 설정이 잘못된 경우입니다. 아웃풋 디렉토리로 설정한 디렉토리가 없을 경우에 오류가 날 수 있습니다. 다시 말해서 c:\tc20\workshop 라는 디렉토리가 없는 상태에서 output 디렉토리로 그 디렉토리를 지정하는 경우입니다. 따라서 책의 환경설정부분을 참고하여 option의 output 디렉토리를 다시 한 번 제대로 설정되었나 확인해보기 바랍니다. 잘 모르겠으면, output 디렉토리로 TC가 깔린 c:\tc20 으로 설정하기 바랍니다.

23.3.8.볼랜드C++에서 textattr 함수를 인식 못합니다.


[질문] 도스용 터보C 컴파일러에서는 textattr란 함수가 사용되는데 볼랜드C++3.1에서는 (윈도용) 그런 함수를 인식을 못합니다. 어찌 된 일일까요?

[답변]
함수는 C언어 본래부터 만들어 사용했던 함수가 있고, 컴파일러에서만 지원하는 함수가 있습니다. 컴파일러 지원함수는 일종의 사용자정의 함수, 즉 라이브러리 함수라 할 수 있습니다. 사용자정의 함수의 개념에 대해서는 책을 참고하시기 바랍니다.

printf() 함수는 C언어가 자체적으로 가지고 있던 오리지날 함수입니다. 그리고 kim() 함수는 제가 만든 사용자정의 함수입니다.

textattr()이라는 함수는 터보C 컴파일러 프로그램에서만 지원하는 함수입니다. 볼랜드사에서 터보C라는 컴파일러를 만들면서 사용자의 편의를 위해 자신들이 만든 사용자정의 함수를 포함시켜준 것입니다. 그것이 볼랜드C++에서는 빠진 것이죠. 그래서 볼랜드C++에는 textattr()이라는 함수가 없는 것입니다.

이처럼 터보C에서만 지원되는 함수, 볼랜드C++이나 비주얼C++에서만 지원되는 함수가 있습니다. 이들 함수는 일종의 사용자정의 함수나 마찬가지이기 때문에 사용하기는 편리하지만 다른 컴파일러 프로그램과 호환되지 않는다는 단점이 있습니다. 즉 비주얼C++에서만 제공하는 함수로 프로그램을 짠 다음에 볼랜드C++에서 컴파일하면 온통 오류 투성이로 나옵니다.

때문에 어떤 컴파일러에서도 오류 없이 컴파일 되도록 하려면 C언어의 오리지널 함수를 사용해서만 프로그램을 만들어야 합니다. 하지만 이렇게 할 경우 프로그램 짜기가 너무 힘들고 기능 구현에 많은 어려움이 있습니다. 특히 그래픽 처리에 관한 경우에는 컴파일러에서 제공하는 함수를 사용하지 않고 사용자가 직접 구현하는 일이 불가능에 가깝습니다.

그러므로 자신에게 맞는 컴파일러를 선택하고, 각 컴파일러에서 지원하는 함수를 따로 배워야 합니다. 컴파일러 라이브러리 매뉴얼이라는 책이 바로 각 컴파일러에서 지원하는 함수를 정리한 책입니다. 컴파일러별로 라이브러리 매뉴얼 책 한 권씩은 비치해야겠죠.

23.3.9.헤더 파일을 적어주었는데도 함수가 선언되지 않았다고 나옵니다.


[질문] conio.h 파일을 포함하고 clrscr() 함수를 사용했는데 선언되지 않았다는 오류가 발생합니다. 이유를 알려주시면 감사하겠습니다.

[답변]
질문이 명확하지 않지만 이런 경우 통상 다음 순서대로 확인하셔야 합니다.

(1) 해당 컴파일러에서 함수를 정의한 헤더 파일을을 지원하는가? 예컨대 clrscr() 함수를 사용한다면 conio.h 파일이 있는가 확인하는 것이 우선입니다. 만약 conio.h 파일이 없다면 당연히 오류가 나겠죠. 모든 컴파일러 프로그램에 coni.h라는 파일이 있는 것이 아닙니다. 터보C 계열 컴파일러에는 conio.h 파일이 있지만 비주얼C++에도 이런 파일이 있는지는 따로 확인하셔야 합니다.

(2) 헤더 파일이 있다면 clrscr() 함수의 헤더 파일이 conio.h 파일인지 확인하셔야 합니다. 이는 conio.h 파일 내용을 읽으면 알 수 있습니다.

(3) conio.h 파일이 있고 clrscr() 함수의 헤더 파일이 conio.h 파일이 맞다면 헤더 파일의 경로가 제대로 지정되었는지 확인해보기 바랍니다.

(4) 마지막으로 명령어가 맞게 사용되었는지, 오타가 있는 것은 아닌지 확인하기 바랍니다.

23.3.10.[No module definition file specified : Using defaults]


[질문] 프로그램을 만든 결과는 나오는데 [No module definition file specified : Using defaults]라는 경고문이 나타납니다.

[답변]
이 경고는 도스용 프로그램인 터보C나 도스용 BC에서는 발생하지 않고 윈도용 볼랜드C++인 BCW에서 발생합니다. 컴파일 과정이 아닌 링크 과정에서 발생하는 경고로 이 경고는 무시하고 프로그램을 만들면 됩니다.

'No module definition file specified'는 말 그대로 해석하면 모듈정의 파일이 없다. 즉 모듈정의 파일이 지정되지 않았다는 뜻입니다.

이 경고문은 TLink 프로그램을 사용할 때 거의 빠지지 않고 나오는 경고문입니다. 윈도용 볼랜드C++로 링크할 때는 Tlink.exe라는 프로그램을 이용합니다. 사용자가 눈치채지 못하게 이 프로그램을 이용하여 링크하는 것이죠. 그런데 Tlink.exe의 사용법은 생각보다 매우 까다롭습니다. 옵션 사용법이 매우 복잡하거든요. Tlink.exe 사용법을 익히려면 볼랜드C++ 매뉴얼을 참고하셔야겠죠.

제 책은 볼랜드C++ 매뉴얼이 아니고 C언어나 C++ 문법설명서이기 때문에 tlink.exe 파일의 사용법을 다루지 않습니다. 이 부분만 다루어도 책으로 한 권 분량이거든요. 그리고 저도 아직 tlink.exe 사용법을 모두 익히지 못한 상태입니다.

결론만 말씀드리면 경고메시지를 무시하고 컴파일과 실행을 진행시키시면 됩니다.

tlink의 메시지는 3가지로 구분됩니다. 치명적 오류 메시지는 링크 자체가 실행되지 않는 경우입니다. 일반적인 오류 메시지는 링크가 실행되어 exe 파일이 만들어지지만 이 파일을 실행할 경우 컴퓨터가 다운되는 등 심각한 문제가 발생할 수 있습니다.

마지막으로 경고문(Warning)이 있는데 이름 그대로 경고에 불과합니다. 주로 환경설정에 문제가 있을 경우 발생합니다. 무시하고 진행해도 exe 파일이 만들어지고 실행하는데 별 지장이 없습니다. 그러므로 질문하신 경고문이 발생하더라도 상관하지 마시고 사용하시기 바랍니다.

이 경고는 변수나 배열 등을 위한 메모리 할당량 문제 때문에 발생합니다. 16비트 컴파일러인 도스용 컴파일러에서는 stack + heap + data group의 메모리 할당량이 64K를 넘으면 안 됩니다. 그런데 도스와 윈도는 메모리 관리 기능이 다릅니다. 이 때문에 발생하는 경고로 BCW가 안고 있는 문제라 할 수 있습니다.

경고 문구는 'TLINK 프로그램을 윈도의 옵션 중 하나로 호출했는데 모듈 정의 파일이 지정되지 않았다'는 뜻입니다. 따라서 모듈 정의 파일을 지정함으로써 문제를 해결할 수 있습니다. 이를 위해서는 모듈 정의 파일을 작성해야 하고, 그 안에는 다음과 같은 내용이 들어가야 합니다.

CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE MULTIPLE
HEAPSIZE 4096
STACKSIZE 5120

그런데 이런 식으로 해결하려면 힙 크기와 스택의 크기가 지나치게 크게 배정되는 문제가 발생합니다. 또한 모듈 정의 파일인 *.def 파일 작성법과 IMPDEF.EXE와 IMPLIB.EXE, Tlink 등의 각종 도구 프로그램 사용법, dll 파일 생성 추출법 등의 다양한 기술을 익혀야 합니다. 이런 내용을 익히려면 방대한 양의 볼랜드C++ 설명서를 통달해야 하는데 이는 고수들이나 가능한 일입니다. 저 또한 def 파일을 사용해본 적이 없을 정도입니다.

그래서 대부분의 볼랜드C++ 프로그래머는 def 파일을 이용하여 이 경고를 없애는 방식을 권장하지 않습니다. 인터넷의 FAQ 문서를 봐도 이 경고가 발생할 경우 대부분의 프로그래머는 이 경고를 무시하고 컴파일하라고 말합니다.

23.3.11.[Square Root of Negative Number]


[질문] 윈도95에서 실행되던 프로그램이 윈도98에서는 문제가 발생합니다. double로 선언된 변수에 cin을 이용해 console입력을 받을 때, 부동소수점 값(예로 8.29, 829e-2 등)을 입력하면 오류가 납니다. 오류 메세지는 "Floating Point : Square Root of Negative Number"입니다. 그런데 정수 값(예로 8)을 입력하면 아무 이상 없이 넘어갑니다. 그리고 프로그램 안에서 값을 넣어주면 또 잘 돕니다.

[답변]
오류 메세지인 "Floating Point : Square Root of Negative Number"를 해석하면 제곱근이 음수를 가진다는 뜻입니다. 음수의 제곱은 '-루트n' 의 형식을 가진 수입니다.(기호로 표현하기 힘들어 말로 표현했습니다.)

그런데 문의한 소스하고 제곱근하고는 아무런 상관이 없죠. 그렇다고 해서 소스 파일에 오류가 있는 것도 아니고. 더 중요한 것은 전에는 이상 없이 실행되었는데 최근에 안 된다는 점입니다.

원인을 알아내야 하는데 원인을 알아내기가 어렵습니다. 이 오류 메시지는 컴파일러 때문에 생기는 것이 아니고 프로그램 실행 과정에서 생기는 운영체제의 오류 메시지이기 때문입니다.
때문에 추측만이 가능할 뿐인데 윈도의 메모리 관리하고 충돌하거나, 윈도이나 볼랜드C++의 실수 관련 dll 파일, 또는 인텔의 x87 계열 보조프로세서와의 충돌 등이 원인일 가능성이 높습니다.

문의하신 오류 메시지는 볼랜드C++의 오류 메시지가 아닙니다. 윈도의 오류 메시지입니. 왜냐하면 볼랜드C++의 오류 메시지라면 컴파일과 링크 도중에 나타나야 하는데 그때 나타나는 것이 아니고, 실행 도중에 나타났으니까요.

이런 오류 메시지는 특히 각종 하드웨어 드라이버를 장착할 때 자주 나타납니다. 주로 윈도3.1 또는 윈도95용 드라이버를 사용할 때 나타나는 메시지입니다. 그외 여러 프로그램의 실행 도중에도 나타납니다.

"Floating Point : Square Root of Negative Number"는 매우 다양한 원인에 의하여 발생합니다. x87계열 프로세서(현재 사용중인 인텔 프로세서는 모두 x87계열이죠)의 오류일수도 있고, DLL 파일 중의 하나가 문제가 될 수도 있습니다. 하여간 "Floating Point : Square Root of Negative Number"가 윈도3.1이나 윈도95에서는 안 나타나던 프로그램을 윈도에서 돌릴 때 나타나는 점으로 미루어 윈도의 메모리 관리나 DLL 파일과의 충돌 때문으로 보여집니다.

원래 문의하신 오류 메시지는 제곱근값과 관련된 오류 메시지로 수학적인 오류가 있을 때 주로 발생합니다. 예를 들어 실수인 숫자를 0으로 나누었을 때 제곱근값(Square Root)의 오류가 되기 때문에 문의한 오류 메시지가 나타납니다. 그러니까 음수의 제곱근을 이용해 연산하거나 수학적인 명제에 어긋나는 계산을 할 경우에 나타납니다.

다음의 예제처럼 변수 a를 0으로 나눌 경우에 문의한 오류 메시지가 나타납니다. 아래의 예제를 볼랜드C++ 3.1 윈도용으로 컴파일해보면 똑 같은 오류 메시지가 나타나는 것을 볼 수 있습니다. 아래의 경우는 수학적인 논리의 오류에 의해 나타나는 현상으로 이런 경우에 "Floating Point : Square Root of Negative Number"라는 메시지가 나타납니다. 물론 a를 2로 나눌 경우에는 b의 값이 0.6이 되므로 b=a/2;라는 문장으로 바꿀 때는 올바른 결과값을 보여줍니다.

#include <stdio.h>
#include

void main(void)
{ float a, b;
a=1.2;
b=a/0;
printf("%f \n",b);
}

알다시피 볼랜드C++ 3.1은 윈도3.1용이지 윈도용이 아닙니다. 그런데 윈도3.1과 윈도95는 16비트 코드를 지원했지만 윈도부터는 16비트 코드 부분의 라이브러리가 많이 삭제되고 32비트용 라이브러리로 바뀌었습니다.(윈도의 운영체제 라이브러리 파일 이야기입니다). 때문에 메모리 관리방법도 바뀌었고, 데이터의 저장 단위도 바뀌었다고 봐야 합니다. 이런 변화 때문에 과거의 프로그램이 정상적으로 동작하지 않습니다. 윈도3.1용 프로그램이 윈도98에서 돌아가지 않거나, 돌아가더라도 약간 비정상적인 모습을 보이는 것은 이 때문입니다. 당연히 볼랜드C++ 3.1로 만든 실행 파일 역시 문제가 발생할 수밖에 없습니다.

볼랜드C++ 3.1이 나온 뒤에 윈도95와 윈도98이 나왔기 때문에 볼랜드C++이 뒤에 나온 운영체제인 윈도에서 정상적으로 동작하기를 바라는 것 자체가 무리입니다. 이는 어쩔 수 없는 일입니다.

따라서 이미 만든 소스 파일을 윈도에서 컴파일하여 정상적으로 동작시키려면 다음의 방법을 사용해야 합니다.
1. 컴파일러를 윈도가 나온 다음에 나온 윈도용 컴파일러(예를 들면 비주얼C++ 6.0이나 볼랜드 C빌더 최신 버전 등)로 컴파일하는 방법
2. 소스 파일을 ANSI C의 함수로 바꾸는 방법
3. 이전의 운영체제로 컴파일하여 그쪽 운영체제에서 사용하는 방법

이중 아마도 최신 컴파일러에서 컴파일하는 1번 방법이 가장 확실한 방법이 될 것입니다.

프로그램 개발자들의 경우 윈도95와 리눅스는 다른 운영체제라고 당연하게 생각하면서도 윈도95와 윈도98, 윈도2000이 서로 다른 운영체제라는 것은 쉽게 인식하지 못합니다. 그러나 이 세 개의 운영체제는 당연히 서로 다른 운영체제입니다. 윈도95용의 일부 프로그램이 윈도98이나 윈도2000에서 별 문제 없이 실행된다고 하여 윈도2000과 윈도95를 같은 운영체제로 인식하면 안됩니다. 더구나 프로그래머라면 당연히 다른 운영체제로 인식해야죠.

몇 가지 소스 파일을 문의하신 오류 메시지가 뜨는 이유는 예제 파일의 문제가 아니라 운영체제의 변화에 따른 어쩔 수 없는 오류라는 사실을 확인할 수 있습니다. 똑 같은 소스 파일을 가지고 TC와 BC, BCW에서 컴파일해보면 이를 확인할 수 있습니다. TC와 BC에서 컴파일한 후에 도스에서 실행할 때는 오류가 안 나타나는데 윈도에서 실행하면 오류가 발생하는 예제를 많이 볼 수 있습니다. 따라서 문의한 오류가 발생하는 경우에는 소스 파일을 윈도98이나 윈도2000에 맞게 수정한 다음에 최신 컴파일러로 컴파일하는 것이 좋습니다.

23.4.C언어 공부에 대한 질문


23.4.1. C를 먼저 배워야 C++을 배울 수 있나요?


[질문] C를 먼저 배워야 C++을 배울 수 있나요? 터보C나 C언어를 모르는 상태에서 비주얼C++로 프로그램 공부를 시작하면 안되나요?

[답변]
C++을 배우기 위해서 C를 알아야 할 필요는 없습니다. 처음부터 C++로 프로그램을 시작해도 상관 없습니다.

물론 비주얼C++을 공부하기 위해서 터보C나 C++을 알아야 할 필요도 없습니다. 한 가지 알아두실 점은 비주얼C++과 보통 말하는 C++이라는 언어와는 많은 차이가 있습니다. 그러므로 비주얼C++을 배울 생각이라면 비주얼C++ 관련 서적만 파고드는 것이 좋습니다.

23.4.2. C++을 배우려고 하는데 C언어를 먼저 배우는 것이 더 효과적인가요?


[질문] C하고 C++하고 어느 것을 먼저 배우는 것이 좋은가요?

[답변]
C++을 배우기 위하여 C언어를 먼저 배워야 할 필요는 없습니다. 다만 C언어를 배운 사람이라면 C++을 배울 때 빨리 배울 수 있습니다. 그 까닭은 C언어를 통해서 이미 언어의 기초를 어느 정도 닦았기 때문입니다.

따라서 꼭 C언어가 아니라 하더라도 비주얼베이직이나 델파이와 같은 다른 언어를 먼저 배웠던 사람은 C++을 배우기가 한결 쉽습니다. 아무래도 컴퓨터 언어의 개념도 모르는 사람이 C++을 배우는 것보다는 컴퓨터 언어를 다루어봤던 사람이 C++을 배우는 것이 훨씬 빠릅니다. 그리고 문법 내용이 전혀 다른 비주얼베이직을 배우고 C++을 배우는 것보다는 문법과 명령어가 거의 일치하는 C언어를 배운 사람이 더 빨리 C++을 배울 수 있습니다.

그렇다면 C와 C++ 중에서 어느 것을 먼저 배우는 것이 더 효과적일까요? 이 문제에 대한 정답은 없습니다. 각기 장단점이 있기 때문입니다.

(1) C++로 공부를 시작한 경우의 장점

C와 C++ 두 개를 배우는 것보다는 C++ 하나만 배우는 것이 아무래도 학습 기간이 좀더 빠릅니다.
또한 C를 먼저 배운 사람에 비해 C++적인 사고력은 더 유연합니다. C를 먼저 배운 사람은 C언어적인 사고를 가지게 됩니다. 이른바 고정 관념 또는 C언어적인 프로그램 습관입니다. 이런 습관은 새로운 습관을 익히는데 방해가 될 수 있습니다. 예를 들어 C언어를 배운 사람은 모듈 중심으로 프로그램을 짜는 습관에 익숙해집니다. 이는 나중에 객체 지향적인 프로그래밍 습관을 익히는데 방해 요인이 될 수 있습니다. 반면 C++로 시작한 사람은 모듈 중심의 프로그램 습관이 배이지 않은 상태라 처음부터 객체 지향 방식의 프로그램 습관을 익히는데 유연하게 적응할 수 있습니다.

(2) C++로 공부를 시작한 경우의 단점

C++로 공부를 시작한 많은 사람들의 경우 C++이 어렵다고 중간에 포기하는 경우가 많습니다. 그래서 C++로 언어 공부를 시작하는 경우 끝까지 공부를 마치는 경우가 드뭅니다. 처음부터 너무 방대하고 어려운 개념이 나오는 언어를 붙잡고 공부하다 보니 다양한 개념을 제대로 이해하지 못하는 것입니다. 이 때문에 C언어를 배우고 C++을 배운 사람이 C++을 더 빨리 이해하고 사용하는 경우가 많습니다.

그리고 C++만 배운 경우에는 C언어가 어떤 식으로 변화했는지 알 수 없습니다. 때문에 다른 언어와 C++이 가지는 차이점을 잘 모릅니다. 즉 C++이 기존의 언어인 C보다 나은 점을 제대로 이해하지 못하는 것입니다. 이는 곧 C++의 장점을 제대로 활용하지 못하는 문제로 연결될 수 있습니다.

(3) C를 먼저 배우고 C++을 배울 경우의 장점

C언어를 제대로 배운 사람이라면 C++을 배울 때 큰 시간이 필요하지 않습니다. 객체 다루는 부분만 제대로 이해하면 됩니다. 때문에 C++을 금방 익힐 수 있습니다.
또한 C를 배우고 C++을 배울 경우 두 언어의 차이점을 압니다. 때문에 C++언어만의 특징과 장점을 확실하게 이해하게 되고, C++언어의 장점을 잘 활용할 수 있습니다.

그리고 C언어로 배울 경우 언어의 기본 개념을 쉽게 익힐 수 있습니다. 물론 C++로도 언어의 기본 개념을 익힐 수 있지만 C언어로 익히는 것보다 힘이 듭니다. C++ 언어는 매우 방대하여 언어의 개념을 익히려면 많은 시간이 투자됩니다. 그러나 C언어는 C++처럼 방대하지 않기 때문에 C언어를 통해서 약간의 시간만 투자해도 컴퓨터 언어의 기초를 다질 수 있다는 장점이 있습니다.

(4) C를 먼저 배우고 C++을 배울 경우의 단점

C언어를 먼저 배울 경우 발생할 수 있는 단점으로는 C언어 프로그램을 하면서 몸에 배인 모듈 중심의 습관을 버리기가 쉽지 않다는 점입니다. 이는 객체 지향 중심의 프로그램을 만드는 C++ 언어에 적응하기 어려운 방해물로 작용합니다.

반면 모듈 중심의 프로그램 습관이 주는 장점도 있습니다. 프로그램의 구조를 단순하고 명쾌하게 이해하는 능력이 생기며, 간단한 프로그램의 경우에는 모듈 중심으로 짜는 것이 훨씬 효율적이기 때문입니다.

결론적으로 말해 C++ 언어를 배우기 위해 C언어를 먼저 배울 필요는 없습니다. 그렇지만 C언어를 먼저 배우고 C++을 배우는 것이 단계적인 학습 효과를 보여주기 때문에 결과적으로 더 효과적인 학습 과정인 경우를 자주 봅니다. 때문에 델파이와 같은 다른 고급 언어를 먼저 배웠던 사람이라면 C++로 바로 공부를 시작해도 좋지만, 처음 컴퓨터 언어에 입문하는 사람이라면 C언어를 먼저 배우고 C++을 배우는 방식을 권장하는 편입니다.

23.4.3. C언어(터보C)로 C++ 프로그램을 만들 수 있나요?


[질문] C언어로도 C++ 프로그램을 만들거나 C++ 소스 파일을 불러올 수 있나요? 그리고 터보C로 C++ 프로그램을 만들 수 있나요?

[답변]
C++은 C언어에서 발전해 나온 것입니다. 때문에 C++ 프로그램으로 C언어 소스 파일을 작성하고 실행 파일을 만들 수 있지만, 반대의 경우는 불가능합니다. C언어 프로그램으로는 C++ 문법을 이용한 프로그램 작성이 불가능합니다.
반면 C++ 프로그램에선 C언어로 프로그램을 작성하고 컴파일하는 것이 가능합니다. 나중에 나온 상위 언어는 하위 언어의 문법을 지원하기 때문입니다.

따라서 '터보C'로는 C언어 소스 파일만 인식하여 컴파일할 수 있습니다. 반면 터보C++. 볼랜드C++로는 C언어와 C++언어 소스 파일을 모두 불러와 컴파일할 수 있습니다.

23.4.4. 윈도2000이라 도스가 없는데 도스가 없어도 C나 C++을 배울 수 있나요?


[질문] 윈도2000을 사용하는데요, 윈도2000에는 도스가 없어요. 도스가 없어도 C언어를 실습하고 배울 수 있나요?

[답변]
도스에서는 C언어를 배울 때 터보C를 사용했고, C++은 볼랜드C++을 사용했습니다. 도스가 지원되지 않는 윈도2000에서는 윈도용 프로그램인 비주얼C++ 이나 윈도용 볼랜드C++, C++ 빌더 등을 사용하면 됩니다. 비주얼C++이나 볼랜드C++로도 C나 C++ 실습이 가능합니다. 그리고 윈도2000에도 도스창이 있습니다. 도스창을 이용하여 도스용 프로그램 실행이 가능합니다.

23.4.5. 비주얼C++보다 IDE 기반의 도스용 C++을 배우는 것이 나은 이유


[질문] 시스템 프로그래밍을 공부하고있으며 회사에서는 TC++3.0, BC++3.1 을 쓰고있습니다. 모 C/C++관련 사이트에 가서 질문을 하면 알고 대답하는건지 왜 아직 도스용 컴파일러를 쓰냐고 구박합니다. 보편적인 시스템 프로그래밍은 도스용 IDE기반 컴파일러를 쓴다고 알고 있는데 어쩔 수 없는 것인가요? 편집도 어렵고 여러 가지로 불편한거 같은데 시스템프로그래머들은 어쩔 수 없이 불편을 감수해야 하는건지 여러 가지로 궁금합니다. 좋은 답변에 항상 감사드립니다.

[답변]
1. 시스템 프로그램에 사용하는 언어는 크게 세 가지입니다. 가장 기본적인 것은 어셈블리어입니다. 어셈블리어는 배우기 무척 어렵습니다. 하드웨어 지식이 먼저 완전하게 갖추어져야 하기 때문입니다. 그렇지만 배우면 가장 유용한(대접받는) 언어입니다. 다음으로 C언어(또는 C++)를 많이 사용합니다. 가장 유연하고 호환성이 좋기 때문입니다. 마지막으로 그 하드웨어 운영체제에서 지원하는 언어입니다. 예를 들어 인터넷이나 모바일(휴대폰 등) 지원 하드웨어라면 자바와 같은 언어를 이용합니다.

어셈블리어는 가장 강력하지만 배우기 어려워 사용하는 사람이 많지 않습니다. 그래서 대개의 경우 C언어나 운영체제에서 사용하는 언어를 이용하여 시스템을 제어합니다.

2. 대개의 프로그램은 C언어나 운영체제에 최적화된 언어를 사용합니다. 윈도에서 프로그램을 짠다면 C나 C++, 델파이, 비주얼베이직, 비주얼C++ 등을 이용합니다. 이 중에서 예나 지금이나 가장 많이 사용하는 언어는 C 계열(C나 C++)입니다. 왜 C를 많이 사용하는 지에 대해서는 본문에 언급한 부분을 참고하기 바랍니다.

3. IDE 기반의 컴파일러가 편집도 어렵고 사용이 불편하다고 하셨는데 이는 IDE 기반의 컴파일러를 제대로 다루지 못한 분의 인식 부족 때문입니다. 어떻게 보면 윈도 환경에서 사용하는 컴파일러에 비하면 IDE 방식의 컴파일러가 더 사용하기 편하고 효율적입니다. IDE 방식의 컴파일러가 불편하다고 말을 한다면 윈도(MS사의 윈도 계열 운영체제)용 프로그램만 만들어본 사람인 경우가 대부분입니다. 다양한 컴파일러를 사용해봤다면 IDE 방식의 컴파일러를 불편한 컴파일러라고 말하지 못합니다.

명령어 방식과 IDE 방식, 윈도 방식의 컴파일러가 있을 경우 고수는 명령어 방식을 선호하고, 중급자는 IDE 방식을, 초급자는 윈도 방식을 선호하기 마련입니다.(꼭 그렇다는 것이 아니고 일반적인 성향이 그렇다는 것입니다) 이는 운영체제를 다루는 사용자들의 경우 고수는 명령어방식(도스나 리눅스)을 선호하고, 중급자는 IDE 방식(윈도커맨드나 도스쉘 등)을, 초급자는 아이콘과 메뉴방식을 선호하는 것으로 비교할 수 있습니다. 왜 고수가 명령어 방식을 선호할까요? 정확하고 빠르기 때문입니다.
예를 들어서 윈도의 탐색기를 이용하여 1만 개 정도 되는 파일의 이름을 바꾸려면 며칠이 걸립니다. 그러나 명령어 방식에서는 불과 몇 초면 끝나는 일입니다. 그래서 저처럼 명령어 방식과 윈도커맨더 같은 쉘 프로그램을 자주 사용하는 사람은 윈도의 탐색기를 거의 사용하지 않습니다.

4. 왜 많은 프로그래머가 C나 C++을 사용하는지에 대해서도 본문에 설명해두었지만 다시 말씀 드리겠습니다. C나 C++은 유연하고 확장성, 호환성이 좋기 때문입니다. 그에 비해 윈도용 프로그램은 확장성 호환성에서 완전히 빵점입니다. 가장 이해하기 쉬운 비유로 언어의 유행을 들겠습니다.

불과 5년 전 가장 유행한 언어는 델파이였습니다. 그 당시 대개의 프로그램 입문자는 델파이만 배우려고 했습니다. 그렇지만 그때도 저는 델파이보다는 언어의 기본인 C를 먼저 배우라고 했습니다. 델파이 등은 운영체제나 컴파일러에 따라서 운명이 달라질 수 있는 언어이기 때문입니다. 지금은 아무도 델파이를 배우려 하지 않습니다. 그렇다면 당시에 델파이로 짠 시스템은 앞으로 어떻게 보수 유지를 할까요?

델파이의 유행은 불과 2~3년을 못 갔습니다. 델파이가 시들해진 1998년부터는 비주얼C++이 크게 유행했습니다. 그나 그것도 한 2~3년만에 시들해졌습니다. 최근 2~3년 사이에는 비주얼베이직이 가장 큰 인기를 끌었습니다. 그러나 이제 비주얼베이직도 시들해졌습니다. 이미 MS사에서는 비주얼베이직을 더 이상 지원하지 않기로 했습니다. 비주얼베이직은 폐기처분되는 것이죠. 따라서 만약 비주얼베이직으로 시스템 프로그램을 만든 회사라면 앞으로 시스템 프로그램을 더욱 발전시키는 고사하고 보수 유지조차도 어렵게 됩니다. 비싼 인력을 들여 개발한 프로그램을 폐기 처분하고 새로운 언어로 새롭게 개발해야 하는 상황이 된 것이죠.

왜 이처럼 델파이, 비주얼C++, 비주얼베이직 등이 불과 2~3년만에 죽어버리는 언어가 되었을까요? 언어라기보다는 운영체제에 의존하는 개발키트이기 때문입니다. 즉 MS사의 윈도 시리즈가 윈도3.1에서 윈도95, 윈도, 윈도2000, 윈도미, 윈도XP 등으로 바뀔 때마다 해당 언어의 호환성과 운영체제의 프로그램 지원 환경이 완전히 바뀌기 때문입니다.

다른 예를 듭시다. 비주얼베이직으로 짠 프로그램이 있다고 합시다. 이 프로그램을 리눅스에서 돌릴 수 있습니까? 유닉스에서 돌릴 수 있습니까? 대형 컴퓨터에서 돌릴 수 있습니까? 아니면 매킨토시를 비롯한 이기종 컴퓨터에서 돌릴 수 있습니까? 불가능하죠. 오로지 IBM-PC와 윈도 운영체제에서만 실행이 가능한 프로그램입니다. 또한 비주얼베이직으로 짠 프로그램이 하더라도 윈도의 버전이 바뀌면 실행되지 않는 경우가 대부분입니다. 그래서 운영체제의 변화에 따라서 운명을 같이 하는 것입니다.

반면 C나 C++은 운영체제에 거의 영향을 받지 않는 언어입니다. 표준 함수로 만든 소스 파일은 어떤 시스템 어떤 운영체제에서도 거의 수정 없이 사용 가능합니다. 윈도에서도, 유닉스나 리눅스에서도, 대형컴퓨터나 미니컴퓨터, 매킨토시 등에서도 사용할 수 있습니다. 그래서 보수 유지, 발전이 손쉽습니다. 이것이 C계열 언어의 장점입니다.

만약 윈도에서 단기간에만 사용할 프로그램을 개발하고자 한다면 윈도용 컴파일러인 비주얼C++이나 비주얼베이직을 이용하는 것이 좋습니다. 예컨대 윈도용 게임을 만들겠다면 비주얼C++을 이용해도 괜찮습니다. 그렇지만 서버용 프로그램을 비주얼베이직으로 만드는 것은 수 십 번 고려한 다음에 결정해야 할 문제입니다. 윈도 외의 시스템에서는 돌아가지도 않고, 비주얼베이직 자체가 폐기될 경우 보수, 유지, 발전이 불가능해지기 때문입니다. 장기적으로 운용해야 할 프로그램이라면 표준 C++을 이용하는 것이 바람직합니다. 예를 들어 홈페이지에서 사용하는 CGI용 게시판 프로그램을 C로 만들었을 때는 어떤 운영체제, 어떤 시스템에서도 오랜 기간 사용이 가능하지만 비주얼베이직으로 만들었다면 운영체제만 바뀌어도 폐기처분 해야 합니다.

C++ 빌더도 좋은 컴파일러이기는 하지만 운영체제 의존성이 크다는 점이 단점입니다. 그래서 아직까지도 C++ 빌더가 아닌 볼랜드 C++을 많이 사용합니다.

5. 결론적으로 프로그래머를 직업으로 삼고자 한다면 C와 C++을 확실하게 배워야 하고, 여력이 된다면 어셈블리어를 배워야 합니다. 이 두 가지 언어만 배우면 나머지 언어는 다 배운 것이나 마찬가지입니다. 즉 볼랜드C++만 제대로 통달했다면 최근 유행하는 C#이나 자바 등은 책 한 번만 봐도 다 알 수 있습니다. 이는 C언어가 언어의 기초를 확실하게 다져주는 언어이기 때문입니다.

그렇지만 비주얼베이직으로 프로그램을 공부했던 사람은 비주얼베이직이 폐기된 지금 다시 새로운 언어를 익혀야 하는데 비주얼베이직에서 배운 내용이 거의 쓸모 없기 때문에 볼랜드C++과 같은 프로그램을 배우려면 처음부터 볼랜드C++을 배운 사람보다 더 어렵게 배워야 합니다. 그 까닭은 비주얼베이직은 사용자가 프로그램을 짜는 방식이 아니라 사용자가 이미 준비된 컴포넌트를 조립하면 컴파일러라 소스 파일을 생성하는 방식을 사용하기 때문입니다.

조금 길게 설명을 드렸는데... 결론은 명령어 방식의 운영체제와 그 운영체제에서 사용하는 명령어 방식의 언어(즉 표준 C++)을 배우는 것이 가장 정석이며, 가장 튼튼하게 기초를 다지는 길이라는 것입니다. 터보C++이나 볼랜드C++을 제대로 통달한다면 언어를 제대로 배운 것이라고 할 수 있죠.

23.4.6.프로그램 실력이 안 느는 이유는 무엇일까요?


[질문] 나름대로 C언어를 공부했는데, 막상 프로그램을 짜려고 하면 막힙니다. 실력이 늘지 않는 것 같아 답답합니다. 어떻게 해야 실력이 늘까요?

[답변]
실력이 늘지 않는 경우는 크게 네 가지 이유로 설명할 수 있습니다.

(1) 개념을 이해하지 않고 함수 설명과 소스 파일 중심으로 배우는 경우

독자 중 한 분은 C언어 과목 낙제생이다가 [C언어 이야기]를 읽고 난 뒤에 100점을 맞았다고 편지를 보냈습니다. 이 분 외에도 많은 분들이 비슷한 편지를 보내주셨습니다. 제 책은 국내에는 없는 유일한 컴퓨터 언어 개념서입니다. 때문에 제 책을 읽은 독자분이라면 언어의 개념은 확실하게 잡을 수 있습니다.

그런데 개념을 잡지 않고 함수 설명과 이의 응용 방법 위주로 공부하면 일정 수준에서 더 이상 진전하지 못합니다. 자료형, 변수, 배열의 개념도 모르는 상황에서 변수와 자료형을 다룬다는 것은 말이 안됩니다. 함수 사용법만을 익혀서 당장 필요한 프로그램을 만들 수는 있지만 복잡한 문제를 만나면 손을 들게 됩니다. 따라서 개념을 익히는 것이 최우선입니다. [C언어 이야기]를 읽은 독자분이라면 적어도 개념 문제로 혼동을 겪는 일은 없습니다. [C언어 이야기]를 끝까지 읽는다면 분명 실력이 느는 것을 느낄 수 있습니다.

(2) 눈으로만 보고 언어를 배우는 경우

실전에 약한 사람의 특징 중 하나는 책을 눈으로만 읽는다는 점입니다. 제 책에도 몇 차례 적었지만 프로그램은 직접 한 글자씩 입력하면서 만들어봐야 합니다. 이런 과정에서 오타도 나고 오류가 발생하는데 이런 문제를 겪으면서 하나씩 문제를 해결하는 기술을 익히는 것입니다. 또한 책에서 언급하지 않는 문제를 직접 만들어봐야 합니다.

아주 간단한 점수 관리 프로그램이나 게임이라도 하나 만들어보지 않는 이상 실전 능력은 크게 향상되지 않습니다. 책에 있는 예제는 눈으로 읽으면 쉽게 이해가 되는데 막상 자신이 프로그램을 만들려고 하면 어떤 방식으로 풀어야할지 모르는 사람이 많습니다. 책을 눈으로 읽었기 때문입니다.

따라서 책의 예제와는 별도로 프로그램을 만들어봐야 합니다. 그래야만 이 문제를 어떻게 풀어야 할 지 생각을 하게 됩니다. 또한 그 과정에서 책에 없는 지식이 더 필요하게 되고, 이를 해결하기 위해 다른 책을 더 사보게 되고. 이런 과정을 통해 자신의 프로그램을 조금씩 완성해갈 때 실전 능력이 생기는 것입니다. 따라서 실전에 약한 분은 눈으로만 책을 읽지 말고 실제로 간단한 프로그램을 만들면서 문제를 해결하는 능력을 배양해야 합니다. 또한 한 권의 책만 볼 것이 아니라 연습문제 관련 서적을 보시면서 스스로 문제를 풀어보도록 노력해야 합니다.

(3) 컴퓨터 기초 지식이 없는 경우

컴퓨터 언어는 잘 하는데 실전에 약하다면 컴퓨터 기초 지식이 없기 때문입니다. 예컨대 파일이 무엇인지 모르는 상태에서 파일 관련 프로그램을 만들 수 없습니다. 그런데 현재의 전산 교육은 파일이 무엇인지 모르는 상태에서 프로그램 짜는 방법만 가르쳐주는 기이한 형태로 진행되고 있습니다. 비트, 메모리, 파일, 스트림에 대한 정확한 이해가 없다면 이를 세밀하게 다루는 프로그램을 만들 수 없겠죠. 그저 알고 있는 방법대로만 만들어보고 안 되면 포기하는 식이 됩니다.

제가 쓴 책 중에 [컴국지]라는 컴퓨터 입문서가 있습니다. 제가 10여년 동안 경험한 모든 지식을 집대성한 책으로 컴퓨터 언어 입문자는 먼저 이 책을 보셔야 합니다. 컴퓨터 프로그래머 입문자라면 언어를 배우기 전에 먼저 [컴국지]를 보기 바랍니다. 많은 도움이 될 겁니다.

(4) 집중력이 부족한 경우

마지막으로 실전에 약한 사람의 특징은 집중력 부족입니다. 영어를 10년 동안 배워도 한 마디 회화를 못하는 사람이 있는가 하면 불과 몇 달 동안의 교육으로도 회화를 꽤 잘 하는 사람이 있습니다. 이는 몇 달 동안 미친 듯이 집중했기 때문에 가능한 일입니다. '언어를 배우려면 미쳐야 한다'는 말이 있습니다. 적어도 단기간 동안 집중적으로 미친 듯이 파고들지 않는다면 오랜 기간 언어를 배운다고 해서 언어 실력이 향상되지 않습니다.

요즘은 좋은 환경에서 컴퓨터 언어를 배울 수 있습니다. 물어볼 곳도 없고 알고 싶은 내용을 담은 책도 없던 10여년 전에 비하면 요즘은 교육 환경이 좋습니다. 인터넷으로 각종 자료를 찾아보거나 물어볼 수 있고, 수 많은 책이 나와 있습니다. 따라서 배우려는 사람의 의지만 있으면 C언어 정도는 가볍게 배울 수 있습니다.

마지막으로 실전에 강해지는 비결을 한 가지 알려 드립니다. 가장 좋은 비결은 언어를 배우면서 동시에 하나의 목표 프로그램을 만드는 것입니다.
제 경우에는 C언어를 배우면서 동시에 전자시집 프로그램을 만들었습니다. 전자시집을 만들기 위해서는 C언어의 기본은 물론이고 그래픽, 한글라이브러리, 포인터, 헤더 파일, 프로젝트 파일 작성, 파일 입출력 등의 다양한 공부가 필요했고 관련 서적을 여러 권 보면서 시집을 완성했습니다. 그 결과 한 달도 되지 않아 어지간한 프로그램은 만들 수 있는 수준이 되었씁니다.

독자 여러분도 C언어 실력이 늘고 싶다면 남이 만든 예제를 분석하지 말고 직접 짜보기 바랍니다. 테트리스 게임이나 전자잡지 프로그램 중에 하나를 만들겠다고 목표를 잡기 바랍니다. 단 이때 남이 만든 테트리스 소스는 보지 말기 바랍니다. 남이 만든 소스를 보면 실력이 안 늡니다. 스스로의 논리와 언어 실력만 가지고 테트리스 게임을 만들기 바랍니다. 그래서 테트리스 게임을 만들 수 있다면 C언어 실력을 확실하게 다졌다고 보셔도 됩니다.

23.4.7.C언어하고 게임 프로그램 하고 관련이 있나요?


[질문] C언어를 배웠는데 지금까지 배운 함수로는 게임을 짤 수 없을 것 같습니다. C언어를 잘 하면 정말로 게임을 만들 수 있나요?

[답변]
과거 도스 시절에는 거의 모든 게임을 C언어로 만들었습니다. 터보C 하나만 가지고도 어지간한 게임과 각종 프로그램을 다 만들었습니다. 그렇지만 윈도 시대에는 C언어만 가지고 게임을 만드는 일이 어렵습니다. 기본적인 C언어의 그래픽함수만으로는 윈도를 제어하거나 그래픽을 제어하는 일이 힘들기 때문입니다.
때문에 윈도용 게임을 만들 때는 윈도용 컴파일러 프로그램인 비주얼C++이나 볼랜드C++을 사용해야 합니다. 또한 이들 프로그램 외에도 SDK와 같은 MS사의 개발 지원 도구 프로그램이 별도로 필요합니다.

제 책을 비롯하여 보통 초보자용 C언어 책에는 C언어의 기본 문법만 설명하고 있기 때문에 입문 책을 읽고 게임을 제작하기는 어렵습니다. C언어 입문 서적을 본 뒤에는 그래픽과 파일 입출력을 다루는 중급 책을 봐야 하고, 다음 단계로 게임 제작을 다루는 책을 읽어야 합니다. 마지막으로 실제로 게임을 제작할 때는 게임 제작에 필요한 라이브러리를 구해야 하고 라이브러리 사용법을 익히면서 게임을 만듭니다.

이처럼 게임 제작은 고난도의 프로그램 작업입니다. 고급 수준에 올라야만 게임 제작이 가능하므로 C언어의 기초부터 차근차근 익히셔야 합니다. 게임 제작을 위해서 C언어를 배우라고 한 것은 꼭 C언어로 게임을 제작하라는 의미가 아니라, C언어가 언어의 기본 개념을 익히는 바탕이 되기 때문입니다. 게임을 제작하고자 한다면 처음부터 화려한 그래픽을 이용한 게임을 제작하려고 해서는 안됩니다. 우선 텍스트로 게임을 만들어보고, 다음으로는 자체 그래픽 함수를 이용하여 간단한 그래픽 게임을 만들고, 마지막에 가서야 화려한 그래픽과 애니메이션이 들어가는 게임을 제작하는 과정을 거치는 것이 순서입니다.

일단 [C언어 이야기] 책을 전부 독파하신 다음에 중급자용 책을 독파하고, 그렇게 여러 권의 책을 읽으면서 차근차근 실력을 쌓으면 게임을 제작할 수 있는 실력이 길러집니다. 게임 제작은 C언어 고수가 되어야 가능한 단계입니다. 이 과정까지 꾸준한 노력이 요구되는 어려운 과정을 거쳐야 합니다.

23.4.8.컴퓨터 학과 아닌 사람이라면 C언어를 배울 필요 없나요?


[질문] C언어는 컴퓨터 학과 학생만 배우나요? 비전공학과 학생도 C언어를 배울 필요가 있나요?

[답변]
프로그램을 짤 생각이 없다면 C언어는 물론이고 컴퓨터언어 자체를 배울 이유가 없습니다. 그러나 컴퓨터 언어를 배우겠다면 C언어를 배우는 것이 가장 좋습니다. C언어는 언어의 기본 개념을 이해하는데 가장 도움이 되는 언어입니다. 즉 C언어를 배운 분이라면 비주얼C++, 델파이, 자바, 자바스크립트 등을 배울 때 며칠 만에 배울 수 있을 정도로 언어의 기본이 다져집니다. 따라서 프로그램에 관심이 있다면 전공에 상관 없이 C언어를 먼저 배우는 것이 좋습니다.

23.4.9.수학을 알아야 C언어를 배울 수 있나요?


[질문] 저는 수학을 잘 못하는데요, C언어를 배우거나 프로그램을 잘 짜려면 수학을 잘 해야 하나요?

[답변]
수학과 C언어는 기본적으로 관련이 없습니다. 물론 계산기나 시뮬레이션 프로그램처럼 수학공식을 이용한 프로그램을 만들고자 한다면 해당하는 수학 공부가 필요하겠죠. 그렇지만 그 외 프로그램 제작에는 별도의 수학 지식이 필요하지 않습니다.

C언어를 잘 하려면 이진수 십진수, 파일 등에 관한 기초적인 개념을 잘 아는 것이 중요합니다. 컴퓨터 기초에 대해서 잘 알고자 한다면 제가 쓴 [컴국지]라는 책을 읽어보기 바랍니다.

23.4.10.C언어를 알아야 해킹을 할 수 있나요?


[질문] 저는 뛰어난 실력의 해커가 되고 싶은데요, 해킹이나 보안을 잘 하려면 C언어를 잘 해야 하나요?

[답변]
해커와 C언어는 직접적인 상관 관계가 없습니다. 해킹은 운영체제와 시스템, 네트웍에 대한 이해가 뛰어날 때 가능합니다. 운영체제와 네트웍 지식만 뛰어나도 해킹이 가능하며 해킹 도구를 사용하여 해킹하는 것이 대부분입니다.

그러나 고급 해커나 뛰어난 보안 실력자가 되려면 C언어를 배우는 것이 좋습니다. 유닉스 리눅스와 같은 운영체제가 C언어로 만든 것이라 C언어를 알면 운영체제의 헛점을 파악하거나 이를 보완할 수 있기 때문입니다.

23.4.11. obj, exe 파일을 추적해 소스 파일을 알아낼 수 있나요?


[질문] obj파일은 기계어로 번역된 파일이고 소스 파일의 보안을 위해서 사용하는 것이라고 알고 있습니다. 그런데 obj 파일이나 exe 파일을 가지고 소스 파일을 알아낼 수는 없나요?

[답변]
obj 파일과 exe 파일은 기계어 파일이므로 정상적으로는 소스 파일을 알아낼 수 없습니다. 그렇지만 기계어의 동작 과정을 추적하면 소스 파일을 알아낼 수 있습니다. 이를 역어셈블리 과정이라고 말합니다. 그리고 역어셈블리를 해주는 프로그램이 많이 있습니다. 이들 역어셈블리 프로그램에 해당 파일을 입력시키면 소스 파일을 만들어줍니다.

그렇지만 이때 역추적을 통해 알아낼 수 있는 소스 파일은 기계어파일 즉, 어셈블리어로 변환되어 나옵니다. 왜 그럴까요? 기계어로 된 파일이기 때문에 기계어로 번역되어 나올 수밖에 없습니다. 그러니까 C언어의 소스 파일로 만들어주는 것은 아닙니다.

구구단 프로그램은 다양한 컴퓨터 언어로 작성할 수 있지만 컴파일하면 기계어로 번역됩니다. 이는 기계어로 된 실행 파일만 컴퓨터가 이해할 수 있기 때문입니다. obj 파일 역시 마찬가지입니다. 때문에 기계어로 번역된 obj, exe 파일을 역추적했을 경우 기계어로 소스 파일을 만들어주는 것입니다.

프로그래머는 C언어, 비주얼베이직, 델파이, 클리퍼 등 수 천 종의 언어로 프로그램을 짤 수 있습니다. 그런데 컴퓨터가 달랑 몇 바이트에 불과한 작은 실행 파일 하나 가지고 무슨 재주로 방대한 라이브러리와 문법을 지원하는 수 천 종의 컴파일러 프로그램의 소스로 만들 수 있습니까. 그래서 컴퓨터는 오직 어셈블리어로만 소스 파일을 추적해줍니다.

어셈블리어를 배운 사람이라면 역어셈블리 과정을 통해 번역된 어셈블리어 소스를 통해 프로그램의 논리적인 흐름을 추적할 수 있습니다. 예컨대 암호화 모듈이 어느 부분에 있고, 어떤 식으로 암호화를 하는 지 알아낼 수 있습니다. 그리고 이 과정을 C언어로 재현한다면 똑 같은 기능을 가진 C언어 소스 파일을 만들 수 있습니다. 이런 방법을 통해 간단한 프로그램의 해킹은 가능합니다.

프로그램의 암호화 기능 없애주는 클랙 파일을 만드는 과정은 이와 같은 역어셈블리 과정을 이용합니다. 역어셈블리 과정으로 만든 어셈블리어 소스 파일 중에서 암호화 부분만 알아내 이 기능을 무력화시키는 프로그램을 만드는 것입니다.
또 정식 등록자로 등록할 수 있는 시리얼 번호를 만드는 키생성 프로그램도 같은 방식을 사용합니다. 역어셈블리어로 파악한 소스 파일을 분석하여 시리얼 번호를 만들어내는 과정을 알아낸 다음에 재현합니다. 따라서 같은 방식으로 시리얼 번호를 생성해낼 수 있는 것입니다.

복사방지 락(lock)이 걸린 파일을 크래킹하여 락을 푸는 방법 역시 이렇게 역어셈블로 실행 파일의 소스 파일을 만든 다음에 락을 체크하는 부분을 삭제하고 이를 다시 컴파일하는 방법을 사용합니다. 원본을 역어셈블한 소스 파일에서 락 검사 부분을 빼고 실행 파일로 만든 것이므로 원본 실행 파일과 똑 같이 실행되겠죠. 잠금 장치 검사 기능만 빠진 상태에서 말입니다.

그렇지만 이런 역어셈블리 작업은 간단한 프로그램에서나 가능한 일입니다. 기계어로 된 소스 파일을 분석하는 일은 무척이나 어렵고 지루한 일입니다. 그 일이 쉽다면 상대방 회사의 프로그램을 쉽게 분석하여 모방작품을 만들어내겠죠. 역어셈블리가 만능이었다면 윈도와 같은 운영체제도 손쉽게 복사해 만들 수 있었을 겁니다.

물론 실제로는 지금도 많은 소프트웨어 회사에서 역어셈블을 통해 상대방 회사 프로그램의 핵심기술을 훔쳐내서 사용하지만 이는 일부 기능의 분석에 주로 사용합니다. 대부분의 경우 역어셈블한 소스를 분석하는 시간보다는 아예 처음부터 짜는 것이 훨씬 빠르고 효과적입니다. 시간, 비용적인 면에서 역어셈블 소스를 분석하는 일이 새롭게 짜는 것보다 훨씬 비효율적이기 때문에 특별한 경우 아니면 역어셈블을 하지 않습니다. 게임 프로그램의 락부분을 체크하여 없앤다거나, 특정 메뉴의 구현기술 등을 파악하고자 할 때 사용하는 정도입니다.

그러니까 일단 기계어로 변환된 파일은 역추적을 해서 나오는 소스 파일이 기계어(어셈블리어) 파일이고, 이 파일을 분석하는 시간과 비용이 아예 처음부터 짜는 것보다 훨씬 비효율적이기 때문에 역어셈블을 하지 않는다는 것입니다. 그리고 어셈블리어를 역추적하여 논리를 파악할 수 있는 실력자라면 차라리 자신이 같은 기능의 프로그램을 짜는 것이 더 쉽습니다. 이런 이유로 기계어로 만들어진 덩치 큰 프로그램은 실질적으로 보안이 가능합니다. 그렇지만 크기가 작은 프로그램이라면 손쉽게 보안 기능을 해체할 수 있습니다.

반면 C언어 소스 파일이 유출되었을 때는 기술 전부가 유출되는 상황이 됩니다. C언어 소스 파일은 사람들이 이해하기 쉬운 문법으로 되어 있어 어지간한 사람은 한 번만 봐도 내용을 모두 파악할 수 있습니다. 이런 이유로 각 기업은 소스 파일의 유출에 각별하게 신경을 쓰는 것입니다.

이런 이유로 소스 파일이 공개된 리눅스는 누구나 컴파일하여 자신만의 운영체제를 만들 수 있지만, 소스 파일이 공개되지 않은 윈98은 아무도 건드리지 못하는 것입니다.

23.4.12. 노트북으로도 프로그램 작업이 가능한가요?


[질문] 주업무가 프로그램입니다. 새로 살 컴퓨터로 노트북을 구입해도 프로그램 작업에 어려움이 없을까요?

[답변]
프로그램용으로 사용한다면 구형 노트북으로도 충분합니다. 일단 운영체제가 실행되는 환경이라면 프로그램 작업에 지장이 없습니다. 프로그램 작업을 위한 컴퓨터라면 성능이 높을 이유가 없습니다. 프로그램 작업은 문서편지이나 스프레드시트 잡업과 비슷한 수준이므로 워드나 엑셀이 실행될 정도의 노트북이면 충분합니다.

23.4.13. 한글 코드 구현 관련 서적


[질문] 한글 코드에 관련된 책이 있으면 알려주세요.

[답변]
한글 코드에 관한 정보를 얻고 싶으면 야후나 구글 사이트에서 한글 코드로 검색했을 때 나오는 사이트를 참고하기 바랍니다. 한글 코드 관련 책으로는 이준희 정내권씨가 1991년도에 출간한 [컴퓨터 속의 한글]이라는 책이 있고, 그외 몇 권이 있습니다. 이 중 한글의 코드와 원리에 대해서 자세하게 설명한 책은 정내권씨가 지은 책이 가장 자세합니다.

아래의 책들이 한글코드와 이의 구현방법에 관한 책들이니 참고하기 바랍니다. 서점에서 구하기 힘든 책이므로 도서관에 가서 빌려보셔야 할 겁니다.

[컴퓨터 속의 한글]

* 이준희.정내권 (정보시대. 1991.12)
* C로 구현하는 한글 처리기법서. 컴퓨터 한글 문제를 크게 한글 처리방식, 한글 코드, 한글 입출력 프로그래밍, 한글 폰트 등으로 분류하여 정리했다.

[컴퓨터속의 한글 이야기]

* 김경석 (영진출판사. 1995.03)
* 한글 전산화를 위한 기초 작업으로 살펴본 한글 가나다순, 한글 사전 편찬전산화를 위한 터닦이, 옛 한글 가나다순, 한글 전산화의 입장에서 살펴본 한글맞춤법의 문제점과 그 해결 방안, 한글 전산화의 입장에서 살펴본 남북한 한글 가나다순의 차이점과 그 통일 방안 등 순으로 구성된 책

[컴퓨터와 한글의 만남]
* 임현모 (정보문화사. 1992.04)
* C언어를 이용해서 한글이 컴퓨터에서 구현되는가를 보여주는 책. 기본적인 C언어와 실용적인 여러 기법을 소개.

[C프로그래밍 논리를 찾아라!]
* 이직창 (정보문화사. 1994.01)
* 누리에 프로그램 제작 방법을 서술한 책. 한글 내장형 프로그램인 관계로 한글 코드 구현방법을 자연스럽게 다루고 있다.

23.4.14. 한글 라이브러리 파일 구하기


[질문] 한글라이브러리 파일을 구합니다. 어디에서 구할 수 있을까요?

[답변]
한글라이브러리는 PC통신망의 프로그램 관련 동아리에서 무료로 구할 수 있습니다. 하이텔이나 천리안의 자료실에 가면 한글라이브러리를 구할 수 있습니다. 요즘은 인터넷을 통해서도 구할 수 있습니다.

터보C용 한글 라이브러리로는 '한'이나 '한라' '허르미' 등이 있습니다. 모두 공개용이므로 어렵지 않게 구할 수 있습니다. 설명서는 가남사에서 발간한 라이브러리 책을 참고하면 됩니다. 과거에는 가남사에서 '한'과 '한라' 라이브러리 책을 출간했지만 지금은 판매하지 않습니다. 따라서 책은 도서관을 이용해 보셔야 합니다.

윈도는 그래픽상태에서 한글을 지원하므로 한글 라이브러리가 따로 필요 없습니다. 비주얼베이직이나 볼랜드씨뿔뿔을 이용해 만들면 됩니다.
반응형