왜 main이 여기서 0을 반환하지 않습니까?


116

나는 방금 읽고 있었다

ISO / IEC 9899 : 201x위원회 초안 — 2011 년 4 월 12 일

5.1.2.2.3 프로그램 종료에서 발견 한

..reaching the } that terminates the main function returns a value of 0. 

에서 return 문을 지정하지 않고 main()프로그램이 성공적으로 실행되면 main의 닫는 중괄호}에서 0을 반환합니다.

그러나 다음 코드에서는 return 문을 지정하지 않았지만 0을 반환하지 않습니다.

#include<stdio.h>
int sum(int a,int b)
{
return (a + b);
}

int main()
{
    int a=10;
    int b=5;
    int ans;    
    ans=sum(a,b);
    printf("sum is %d",ans);
}

엮다

gcc test.c  
./a.out
sum is 15
echo $?
9          // here it should be 0 but it shows 9 why?

69
사양을 읽는 인내심을 가진 +1 .....
Asher

16
gcc그 자체로 (버전 4.6.2의 경우) C와 매우 비슷하지는 않지만 매우 유사한 언어를 컴파일합니다. C89를 기반으로 "느슨하게"언어 인 GnuC89를 컴파일합니다.
pmg

2
온 괄호 return문에이 sum()불필요하다. int main()이어야합니다 int main(void).
Keith Thompson

24
혼란! = 오타. 내 키보드에서 '0'과 'o'는 쉽게 후자가 될만큼 가깝습니다. ;-)
The111

2
IMHO는 암시적인 "return 0"을 추가하여 컴파일러가 "main"함수를 특별한 방식으로 관리하도록 강제하기 때문에 상당히 어리석은 사양입니다. 따라서 "main"이라는 함수는 약간 다른 방식으로 작동합니다. 컴파일 시간 검사 ( "반환 값 없음"과 유사)는 어떻습니까?
Giuseppe Guerrini 2011

답변:


141

이 규칙은 1999 년 버전의 C 표준에 추가되었습니다. C90에서 반환 된 상태는 정의되지 않았습니다.

-std=c99gcc 로 전달 하여 활성화 할 수 있습니다 .

부수적으로, 흥미롭게도 9 printf개 문자를 썼던 리턴이므로 9가 리턴 됩니다.


40
또는 return 0;닫기 전에 추가 할 수 있습니다 }. 무해하며 프로그램을 이전 컴파일러로 이식 할 수 있습니다.
Keith Thompson

2
@ Mr.32 : 좋은 관찰입니다. printf ()는 문자열의 길이를 반환하므로 메인의 "반환"인 9가됩니다 (-std = c99를 사용하지 않음).
Hicham 2011

1
@cnicutar : 함수는 일반적으로 스택에 작은 값을 반환하지 않습니다. 왜냐하면 단순히 이동과 반환이 아니라 팝, 푸시 및 점프를 포함하기 때문입니다. 따라서 거의 확실히 레지스터, eax특히 x86 에서 그렇습니다 .
Jon Purdy 2011

8
예, x86 API는 일반적으로 eax레지스터 를 통해 값과 같은 정수를 반환합니다 . 자세한 내용은 en.wikipedia.org/wiki/X86_calling_conventions#cdecl 을 참조하십시오.
Sylvain Defresne 2011

2
여러 번 "return bar ()"가 의도 된 "int foo (void) {bar ();}"와 같은 코드를 보았습니다. 이 코드는 명백한 버그에도 불구하고 대부분의 프로세서에서 잘 작동합니다.
ugoren

15

printf실제로 인쇄 된 문자의 수인 반환 값을 반환합니다 .


이 질문은 프로그램을 실행할 때 콘솔에 인쇄되는 내용에 대해 이야기하지 않고 프로그램의 반환 값에 대해 이야기합니다. )
Hicham 2011

1
@eharvest %errorlevel%Windows에서 확인하는 방법을 모르지만 mainLinux에서 종료 코드와 반환 값 사이에 차이가 있습니까?
Summer_More_More_Tea

1
@eharvest : 대답은 콘솔에 인쇄 된 내용에 대해서도 언급하지 않습니다. 이 경우 반환 값printf 이 9이고 main특정 gcc 버전을 사용할 때 어떻게 든 종료 코드로 "승격"되는 에 대해 설명합니다 .
AH

죄송합니다. 내 실수. 당신이 옳습니다. 내가 너무 빨리이 답변을 읽어 : /
히참

1
이것은 보장 되지 않습니다 . C89 / C90에서이 경우 반환되는 상태는 정의되지 않습니다 . 그것은 무엇이든 될 수 있습니다. 컴파일러가 다른 것을 반환하려고 노력하지 않았기 때문에 9를 반환합니다. 다른 컴파일러는 다르게 동작 할 수 있습니다.
Keith Thompson

6

함수의 반환 값은 일반적으로 cpu의 eax 레지스터에 저장되므로 "return 4;"문은 일반적으로 컴파일됩니다

mov eax, 4;
ret;

반환 x (컴파일러에 따라 다름)는 다음과 같습니다.

mov eax, [ebp + 4];
ret;

반환 값을 지정하지 않으면 컴파일러는 여전히 "ret"을 뱉어 내지 만 eax의 값을 변경하지 않습니다. 따라서 호출자는 이전에 eax 레지스터에 남은 것이 반환 값이라고 생각할 것입니다. 이 예제의 경우 일반적으로 반환 값 printf이지만 다른 컴파일러는 다른 기계 코드를 생성하고 일부 레지스터를 다르게 사용합니다.

이것은 간단한 설명이며, 다양한 호출 규칙과 대상 플랫폼이 중요한 역할을 할 것이지만 예제에서 '뒤에서'무슨 일이 일어나고 있는지 설명하기에 충분한 정보 여야합니다.

어셈블러에 대한 기본적인 이해가 있다면 다른 컴파일러의 디스 어셈블리를 비교할 가치가 있습니다. 일부 컴파일러는 보호 수단으로 eax 레지스터를 지우고 있음을 알 수 있습니다.


11
컴파일러 그렇게 할 수 있습니다 . 정의되지 않았습니다. 대신 프린터 카트리지로 머리를 쏘도록 선택할 수 있습니다.
궤도의 가벼운 경주

@LightnessRacesinOrbit undefined는 예측할 수없는 것과 동일하지 않습니다. 즉, "컴파일러가 X를 수행하면 표준을 준수합니다"에서 논리적으로 "컴파일러가 X를 수행 할 수 있습니다"를 따르지 않습니다.
Owen

@Owen : 이것을 정의하는 표준 구절을 인용하십시오.
밝기 경주 궤도에

2
@LightnessRacesinOrbit 제가 따라하지 못해서 죄송합니다. 내가 정말로 말하고 싶은 것은이 답변에서 제공된 noggin182와 같은 내부 통찰력이 디버깅에 매우 유용하다고 생각한다는 것입니다. 프로그램이 예상치 못한 결과를 생성 할 때, 그 결과가 어디에서 왔는지 또는 코드에서 찾을 위치를 모르는 경우가 많으며 구현 세부 사항을 이해하면 올바른 방향을 가리킬 수 있습니다.
Owen

@Owen 나는 달리 주장한 적이 없다
궤도의 Lightness Races
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.