이것을 꼭 지켜주시면 꼬일일이 없습니다. 그리고 그렇게 하라고 구분해 놓은것이 저것들입니다.
따라서 헤더에서 소스를 include한다든가 하는 것은 매우 안좋은 설계입니다.
가끔 소스에서 다시 소스를 include하는 설계도 있는데 이것도 매우 안좋은 설계입니다.
-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.
이므로 main() 함수에서 hello() 함수를 호출하기 전에 hello() 함수가 선언됨으로써 hello() 함수의 이름과 형, 그리고 함수의 존재 여부를 알 수 있습니다. (물론, 실재로는 존재하지 않거나 형이 다를 수도 있습니다.)
따라서, 이후에 hello() 함수를 쓸 수 있게 되는 거죠.
"a.h"의 파일 이름을 "asdf.c"로 바꾼 다음, 모든 #include "a.h" 를 #include "asdf.c"로 바꾸면 정확하게 똑같이 컴파일 됩니다. 심지어 "asdf"나 "asdf.exe" 등 어떤 이름도 상관 없습니다.
파일 확장자가 파일의 종류를 결정짓는 것이 아니라, 파일 내용으로부터 이미 결경된 파일의 종류에 따라 파일 이름에 접미사를 붙여 구분지어 놓은 것에 불과하기 때문입니다.
간단합니다. void func(); void
간단합니다.
이 둘의 차이입니다.
헤더파일이 아니더라도 그냥 일반 시 파일에 넣어서
헤더파일이 아니더라도 그냥 일반 시 파일에 넣어서 include 해줘도 작동을 하는데
왜 헤더파일을 쓰는지 궁굼합니다.
h는 선언 c(pp)는 정의를 하도록
h는 선언 c(pp)는 정의를 하도록 되어있는데
만약 프로그램이 커져서
하나의 함수, 변수를 다른 여러개의 파일에서 쓸 수 있을텐데
만약 둘을 분류하지 않고
h에만 정의까지 해둔다면
다중정의가 되서 에러를 뿜습니다.
선언은 헤더 구현은 소스 이것을 꼭 지켜주시면
선언은 헤더
구현은 소스
이것을 꼭 지켜주시면 꼬일일이 없습니다. 그리고 그렇게 하라고 구분해 놓은것이 저것들입니다.
따라서 헤더에서 소스를 include한다든가 하는 것은 매우 안좋은 설계입니다.
가끔 소스에서 다시 소스를 include하는 설계도 있는데 이것도 매우 안좋은 설계입니다.
-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.
#include는 지정된 파일을 단순 삽입하라는
#include는 지정된 파일을 단순 삽입하라는 지시어입니다. 헤더파일과 소스파일은 사실은 단순한 텍스트파일이고, 단지 c 문법에 맞게 선언과 구현, 또는 선언만으로 구성되어 있을 뿐이죠.
"a.h"와 "a.c"가 다음과 같을 때,
"a.h"
"a.c"
"a.c"를 컴파일하면, 컴파일러가 파싱하는 구문은 실제로는 다음과 같습니다.
"b.c"가 있어서
컴파일하면 파싱되는 구문은
이므로 main() 함수에서 hello() 함수를 호출하기 전에 hello() 함수가 선언됨으로써 hello() 함수의 이름과 형, 그리고 함수의 존재 여부를 알 수 있습니다. (물론, 실재로는 존재하지 않거나 형이 다를 수도 있습니다.)
따라서, 이후에 hello() 함수를 쓸 수 있게 되는 거죠.
"a.h"의 파일 이름을 "asdf.c"로 바꾼 다음, 모든 #include "a.h" 를 #include "asdf.c"로 바꾸면 정확하게 똑같이 컴파일 됩니다. 심지어 "asdf"나 "asdf.exe" 등 어떤 이름도 상관 없습니다.
파일 확장자가 파일의 종류를 결정짓는 것이 아니라, 파일 내용으로부터 이미 결경된 파일의 종류에 따라 파일 이름에 접미사를 붙여 구분지어 놓은 것에 불과하기 때문입니다.
덧붙이자면,"a.c" 컴파일한 결과가
덧붙이자면,
"a.c" 컴파일한 결과가 "a.obj", "b.c" 컴파일한 결과가 "b.obj"라면
"a.obj" 안에는 _hello 라는 이름의 컴파일된 (기계어로 된) 함수와
"b.obj" 안에 _main 라는 이름의 컴파일된 함수가 생기게 됩니다.
(사실 함수인지 변수인지조차 모르고 이름만 남아있을 뿐입니다.)
둘을 linker가 "b.obj"에서 _main 이라는 함수를 찾아 프로그램의 시작점으로 삼고, _main 에서 참조한 _hello 함수를 "a.obj"에서 찾아 실제 주소로 바꾸어 줍니다.
만약, "c.c"라는 소스파일이 추가되었고 "a.h" 를 include한다고 한다면, 문제가 없습니다.
"b.c", "c.c"에서 "a.h" 대신 "a.c"를 include한다면, 역시 컴파일에는 문제가 없습니다.
하지만 "a.obj"에도 _hello가 생기고, "c.obj"에도 _hello가 생기게 됩니다.
문제는 linker가 _hello 함수를 찾을 때 같은 이름의 _hello가 두 개가 존재하므로 에러를 뿜어냅니다.
반대로 "a.c"를 지워버리면, 어디에서도 _hello를 찾을 수 없어서 에러가 발생합니다.
사실 "a.c"에서는 "a.h" 를 반드시 include할 필요는 없습니다만, 개인적으로 해 주는 것이 좋다고 생각합니다.
"a.c"를 다음과 같이 업데이트 한 상황을 생각해 봅시다. "a.h"는 실수로 고치지 않았습니다.
_hello는 정상적으로 생성이 되지만 main 에서는 'void hello();' 처럼 사용하고 있습니다. 컴파일, 링크 모두 정상적으로 이루어지지만 런타임에 에러가 날 수 밖에 없는 상황입니다.
만약, 주석처리된 부분을 고쳐서
를 컴파일할 때,
선언 void hello(), 구현 void hello(int a) 의 불일치로 컴파일 과정에서 에러가 발생하므로,
"a.h"가 잘못되었다는 것을 즉시 파악하고, 바로 고칠 수 있습니다.
댓글 달기