값을 반환하지 않고 비 전반 기능의 끝에서 흐르면 컴파일러 오류가 발생하지 않습니까?

StackOverflow https://stackoverflow.com/questions/1610030

  •  05-07-2019
  •  | 
  •  

문제

몇 년 전에 깨달은 이후로, 이것이 기본적으로 (적어도 GCC에서) 오류가 발생하지 않는다는 것을 깨달았습니다.

경고를 생성하기 위해 컴파일러 플래그를 발행 할 수 있다는 것을 이해하지만 항상 오류가되어서는 안됩니까? 비 전역 함수가 값을 유효하게 반환하지 않는 것이 합리적입니까?

의견에 요청 된 예 :

#include <stdio.h>
int stringSize()
{
}

int main()
{
    char cstring[5];
    printf( "the last char is: %c\n", cstring[stringSize()-1] ); 
    return 0;
}

... 컴파일.

도움이 되었습니까?

해결책

C99 및 C ++ 표준은 값을 반환하기 위해 함수를 요구하지 않습니다. 값 회복 함수에서 누락 된 반환 명령문이 정의됩니다 (Return로 0) 만 main 기능.

이론적 근거에는 모든 코드 경로가 값을 반환하는지 확인하는 것이 매우 어렵고, 임베디드 어셈블러 또는 기타 까다로운 방법으로 반환 값을 설정할 수 있습니다.

에서 C ++ 11 초안:

§ 6.6.3/2

함수의 끝에서 흐르면 [...]는 가치 회복 함수에서 정의되지 않은 동작을 초래합니다.

§ 3.6.1/5

제어가 끝나는 경우 main a return 진술, 그 효과는 실행의 효과입니다

return 0;

C ++ 6.6.3/2에 설명 된 동작은 C에서 동일하지 않습니다.


-Wreturn 유형 옵션으로 호출하면 GCC가 경고를 제공합니다.

-wreturn 유형 함수가 int로 기본적으로 반환 유형으로 정의 될 때마다 경고합니다. 또한 return- 타입이 무효화되지 않은 함수에 반환 값이없는 리턴 명령문 (함수의 끝에서 떨어지는 것은 값없이 리턴으로 간주됩니다) 및 함수의 표현식이있는 반환 문에 대해서도 경고합니다. 리턴 유형은 무효입니다.

이 경고는 다음과 같이 가능합니다 -벽.


호기심과 마찬가지로이 코드가 무엇을하는지보십시오.

#include <iostream>

int foo() {
   int a = 5;
   int b = a + 1;
}

int main() { std::cout << foo() << std::endl; } // may print 6

이 코드는 공식적으로 정의되지 않은 동작을 가지고 있으며 실제로는 전화 컨벤션 그리고 건축물 매달린. 하나의 특정 시스템에서 하나의 특정 컴파일러를 사용하여 리턴 값은 마지막 표현식 평가의 결과입니다. eax 해당 시스템 프로세서의 등록.

다른 팁

GCC는 기본적으로 모든 코드 경로가 값을 반환하는지 확인하지 않습니다. 일반적으로이를 수행 할 수 없기 때문입니다. 그것은 당신이 무엇을하고 있는지 알고 있다고 가정합니다. 열거를 사용하여 일반적인 예를 고려하십시오.

Color getColor(Suit suit) {
    switch (suit) {
        case HEARTS: case DIAMONDS: return RED;
        case SPADES: case CLUBS:    return BLACK;
    }

    // Error, no return?
}

당신은 프로그래머가 버그를 제외 하고이 방법이 항상 색상을 반환한다는 것을 알고 있습니다. GCC는 자신이하고있는 일을 알고 있다고해서 기능의 맨 아래에 반환을하도록 강요하지 않습니다.

반면에 Javac은 모든 코드 경로가 값을 반환하고 모두가 자신이하는 것을 증명할 수없는 경우 오류를 던진다는 것을 확인하려고합니다. 이 오류는 Java 언어 사양에 의해 의무화됩니다. 때로는 잘못되었고 불필요한 반환 명령문을 제시해야합니다.

char getChoice() {
    int ch = read();

    if (ch == -1 || ch == 'q') {
        System.exit(0);
    }
    else {
        return (char) ch;
    }

    // Cannot reach here, but still an error.
}

철학적 차이입니다. C 및 C ++는 Java 또는 C#보다 허용적이고 신뢰할 수있는 언어이므로 최신 언어의 일부 오류는 C/C ++의 경고이며 일부 경고는 기본적으로 무시되거나 꺼집니다.

당신은, 가치 회복 함수의 끝에서 흐르는 이유 (즉, 명시 적없이 종료 return) 오류가 아닌가?

첫째, 함수가 의미있는 것을 반환하는지 여부는 실제로 실행 코드가 실제로 실행 될 때만 중요합니다. 용도 반환 된 값. 어쨌든 대부분의 시간을 사용하지 않을 것이라는 것을 알면 언어가 당신이 무엇이든 반환하도록 강요하고 싶지 않았을 것입니다.

둘째, 언어 사양은 컴파일러 저자가 명시 적 존재에 대한 가능한 모든 제어 경로를 감지하고 확인하도록 강요하고 싶지 않았습니다. return (많은 경우에 이것은 그렇게 어렵지는 않지만). 또한 일부 제어 경로가 이어질 수 있습니다 비 회전 기능 - 일반적으로 컴파일러에 알려지지 않은 특성. 그러한 경로는 성가신 잘못된 긍정적 인 긍정적 인 원천이 될 수 있습니다.

또한 C와 C ++는이 경우 동작의 정의가 다르다는 것을 주목하십시오. C ++에서 값의 끝에서 흘러 나오는 반환 함수는 항상 정의되지 않은 동작입니다 (함수의 결과가 호출 코드에서 사용되는지 여부에 관계없이). C에서는 호출 코드가 반환 된 값을 사용하려고 시도하는 경우에만 정의되지 않은 동작을 유발합니다.

C/C ++에 따라 무언가를 반환한다고 주장하는 함수에서 돌아 오지 않는 것이 합법적입니다. 통화와 같은 많은 사용 사례가 있습니다. exit(-1), 또는 그것을 호출하거나 예외를 던지는 함수.

컴파일러는 UB로 이어지더라도 법적 C ++를 거부하지 않을 것입니다. 특히, 당신은 요구하고 있습니다 경고가 없습니다 생성됩니다. (GCC는 기본적으로 여전히 일부 켜지지 만 추가하면 이전 기능에 대한 새로운 경고가 아닌 새로운 기능과 일치하는 것 같습니다)

기본 No-Arg GCC를 일부 경고를 방출하도록 변경하는 것은 기존 스크립트 또는 시스템에 대한 변화가 될 수 있습니다. 잘 디자인 된 것 -Wall 경고를 처리하거나 개별 경고를 전환합니다.

C ++ 도구 체인 사용을 배우는 것은 C ++ 프로그래머가되는 법을 배우는 데 장애가되지만 C ++ 도구 체인은 일반적으로 전문가가 작성합니다.

어떤 상황에서 오류가 발생하지 않습니까? 반환 유형을 선언하고 무언가를 반환하지 않으면 나에게 오류처럼 들립니다.

내가 생각할 수있는 한 가지 예외는입니다 main() 필요하지 않은 함수 return 전혀 진술 (적어도 C ++; 나는 C 표준 중 하나가 없다). 반품이 없으면 마치 마치 return 0; 마지막 진술입니다.

컴파일러 경고를 시작 해야하는 것 같습니다.

$ gcc -Wall -Wextra -Werror -x c -
int main(void) { return; }
cc1: warnings being treated as errors
<stdin>: In function ‘main’:
<stdin>:1: warning: ‘return’ with no value, in function returning non-void
<stdin>:1: warning: control reaches end of non-void function
$

나는 이것이 레거시 코드 때문이라고 생각합니다 (C는 절대 반환 명령문이 필요하지 않으므로 C ++도 필요하지 않습니다). 아마도 "기능"에 의존하는 거대한 코드 기반이있을 것입니다. 그러나 적어도 거기에 있습니다 -Werror=return-type 많은 컴파일러 (GCC 및 Clang 포함)의 플래그.

C99의 제약 위반이지만 C89는 아닙니다. 차이:

C89 :

3.6.6.4 return 성명

제약

return 표현식이있는 명령문은 반환 유형이있는 함수에 나타나지 않아야합니다. void .

C99 :

6.8.6.4 return 성명

제약

return 표현식이있는 명령문은 반환 유형이있는 함수에 나타나지 않아야합니다. void. ㅏ return 표현이없는 명령문은 반환 유형이있는 함수에만 나타납니다. void.

심지어 --std=c99 모드, GCC는 경고 만 던지는 것입니다 (추가를 활성화 할 필요없이 -W 기본적으로 또는 C89/90에서 요구되는 플래그.

C89에 추가하도록 편집하십시오. } 종료 된 함수는 a를 실행하는 것과 같습니다 return 표현이없는 진술 "(3.6.6.4). 그러나 C99에서는 동작이 정의되지 않았습니다 (6.9.1).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top