게시판 즐겨찾기
편집
드래그 앤 드롭으로
즐겨찾기 아이콘 위치 수정이 가능합니다.
fn(), fn(void) 와 main(), main(void)
게시물ID : humorbest_1033284짧은주소 복사하기
작성자 : 상상속동물
추천 : 45
조회수 : 5054회
댓글수 : 15개
베스트 등록시간 : 2015/03/19 15:27:21
원본글 작성시간 : 2015/03/10 09:26:02

아래 이미 답변이 나왔지만, 
반박 글도 나왔고 답변 해주신 분들이 언제 올지도 모르고 해서 
정리하는 글을 올려볼까 합니다. 

갓 스택오버플로우의 답변을 먼저 참고하시고, 
http://stackoverflow.com/questions/13876868/void-mainvoid-vs-main

갓스택오버플로우의 형님들의 답변에 따르면 C99에서 void는 '없음'을 뜻합니다. 
따라서 이론상 C99에서 fn(void)는 인자가 없어야 됩니다. 
확인해보실까요? 

void func(void) {
int blahblah = 1;
blahblah++;
}
int main() {
func(152);
return 0;
}
WhoAmI$ gcc -O0 -std=c99 argvoid.c -o argvoid
argvoid.c:8:7: error: too many arguments to function call, expected 0, have 1
func(152);
~~~~ ^~~
argvoid.c:2:1: note: 'func' declared here
void func(void) {
^
1 error generated.
두둥. 에러가 뜹니다. 이론대로 0개의 인자를 받아야하는 함수라고 에러메시지를 보여줍니다. 
그럼 아무것도 넣지 않은 경우는 어떨까요? 
void func() {
int blahblah = 1;
blahblah++;
}
int main() {
func(153, 154, 155);
return 0;
}
WhoAmI$ gcc -O0 -std=c99 argnothing.c -o argnothing
argnothing.c:8:20: warning: too many arguments in call to 'func'
func(153, 154, 155);
~~~~ ^
1 warning generated.
경고만 줍니다. 
에러를 내뿜어야 당연한게 아닌가 하는 생각이 들지만, 이것은 컴파일러가 컴파일하는 규칙에 의한 결과물이므로 그냥 넘어가겠습니다. 사실 이렇게 사용하는 사람도 없잖아요? 해당 결과는 컴파일러마다 다를 수 있습니다. 다른 분이 올린 것처럼 vc는 해당 표준을 구현하지 않았거나 무시할 수도 있습니다. 


그럼 이번에는 원래 질문인 main()과 main(void)가 차이가 있는지 없는지를 한번 살펴보도록 하죠. 
앞선 결과를 보면 main(void)는 어떤 인자도 받아들이지 않겠다고 명시적으로 선언했습니다. 

int main() {
int a = 152 + 312;
return 0;
}
int main(void) {
int a = 152 + 312;
return 0;
}
컴파일 결과 둘다 에러는 발생하지 않습니다.
컴파일 결과물도 동일합니다. 확인해보시죠. 
emptymain`main:
-> 0x100000f80: pushq %rbp
0x100000f81: movq %rsp, %rbp
0x100000f84: movl $0x0, %eax
0x100000f89: movl $0x0, -0x4(%rbp)
0x100000f90: movl $0x1d0, -0x8(%rbp)
0x100000f97: popq %rbp
0x100000f98: retq

voidmain`main:
-> 0x100000f80: pushq %rbp
0x100000f81: movq %rsp, %rbp
0x100000f84: movl $0x0, %eax
0x100000f89: movl $0x0, -0x4(%rbp)
0x100000f90: movl $0x1d0, -0x8(%rbp)
0x100000f97: popq %rbp
0x100000f98: retq
그럼 main()하고 main(void)를 호출하는 녀석은 어떻게 생각하고 있을까요? 

(lldb) bt
* thread #1: tid = 0x44e6e, 0x0000000100000f80 emptymain`main, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x0000000100000f80 emptymain`main
frame #1: 0x00007fff98dd35c9 libdyld.dylib`start + 1
Mac에서는 libdyld.dylib의 start에서 main함수를 호출합니다. 

(lldb) r 'testempty'
Process 33860 launched: '/Users/WhoAmI/llvm/emptymain' (x86_64)
Process 33860 stopped
* thread #1: tid = 0x4764c, 0x0000000100000f80 emptymain`main, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000100000f80 emptymain`main
emptymain`main:
-> 0x100000f80: pushq %rbp
0x100000f81: movq %rsp, %rbp
0x100000f84: movl $0x0, %eax
0x100000f89: movl $0x0, -0x4(%rbp)
(lldb) x/12xw $rsp
0x7fff5fbffbb8: 0x98dd35c9 0x00007fff 0x98dd35c9 0x00007fff
0x7fff5fbffbc8: 0x00000000 0x00000000 0x00000002 0x00000000
0x7fff5fbffbd8: 0x5fbffce0 0x00007fff 0x5fbffcfd 0x00007fff
(lldb) x/s 0x7fff5fbffcfd
0x7fff5fbffcfd: "testempty"

(lldb) r 'testvoid'
Process 33865 launched: '/Users/WhoAmI/llvm/voidmain' (x86_64)
Process 33865 stopped
* thread #1: tid = 0x47677, 0x0000000100000f80 voidmain`main, queue = 'com.apple.main-thread', stop reason = breakpoint 3.1
frame #0: 0x0000000100000f80 voidmain`main
voidmain`main:
-> 0x100000f80: pushq %rbp
0x100000f81: movq %rsp, %rbp
0x100000f84: movl $0x0, %eax
0x100000f89: movl $0x0, -0x4(%rbp)
(lldb) x/12xw $rsp
0x7fff5fbffbc8: 0x98dd35c9 0x00007fff 0x00000000 0x00000000
0x7fff5fbffbd8: 0x00000002 0x00000000 0x5fbffce8 0x00007fff
0x7fff5fbffbe8: 0x5fbffd04 0x00007fff 0x00000000 0x00000000
(lldb) x/s 0x7fff5fbffd04
0x7fff5fbffd04: "testvoid"

프로세스를 만들어 main함수를 호출하는 과정에서 
main()으로 선언했든 main(void)로 선언했든 int argc, char* argv를 인자로 넘겨주는 것을 확인할 수 있습니다. 

고로 컴파일하는 것은 불가능 하더라도, main()이나 main(void)에 인자를 넘겨주는 것은 재량입니다. 

결론, 
main() 와 main(void)는 차이가 없습니다.
fn()과 fn(void)는 컴파일러에 따라 인자를 넘기면 에러 혹은 경고를 냅니다. 



꼬릿말 보기
전체 추천리스트 보기
새로운 댓글이 없습니다.
새로운 댓글 확인하기
◀뒤로가기
PC버전
맨위로▲
공지 운영 자료창고 청소년보호