programing

값을 반환하지 않고 비포이드 함수의 끝에서 흘러내리면 컴파일러 오류가 발생하지 않는 이유는 무엇입니까?

itsource 2022. 8. 17. 21:52
반응형

값을 반환하지 않고 비포이드 함수의 끝에서 흘러내리면 컴파일러 오류가 발생하지 않는 이유는 무엇입니까?

디폴트로는 (적어도 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++ 규격에서는 함수를 사용하여 값을 반환할 필요가 없습니다.됩니다).0 )의 만)main★★★★★★ 。

모든 코드 패스가 값을 반환하는지 여부를 확인하는 것은 매우 어려우며 반환 값은 삽입 어셈블러 또는 기타 까다로운 메서드를 사용하여 설정할 수 있습니다.

C++11 드래프트에서:

§ 6.6.3/2

함수 [...]의 끝에서 흘러내리면 정의되지 않은 동작이 값 반환 함수에서 발생합니다.

§ 3.6.1/5

가 의 에 main 않고return 것은, 「실행하면 」, 「실행하면 가 있다」라고 하는 것입니다.

return 0;

C++ 6.6.3/2에 기재되어 있는 동작은 C와 동일하지 않습니다.


-Wreturn-type 옵션을 사용하여 호출하면 gcc에 경고가 표시됩니다.

- Wreturn-type 기본 int 반환 유형으로 함수가 정의될 때마다 경고합니다.또한 반환 유형이 void가 아닌 함수(함수 본체의 끝에서 떨어지는 것은 값 없이 반환되는 것으로 간주됨)에서는 반환 값이 없는 반환 문에 대해 경고하고 반환 유형이 void인 함수에서는 식이 포함된 반환 문에 대해서도 경고합니다.

이 경고는 -Wall에 의해 유효하게 됩니다.


참고로 이 코드의 기능을 확인해 주십시오.

#include <iostream>

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

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

이 코드는 공식적으로 동작을 정의하지 않았으며 실제로는 규칙아키텍처의존합니다.특정 시스템에서 특정 컴파일러를 1개 사용하는 경우 반환값은 마지막 표현식 평가의 결과이며,eax이치노

것이 닫는다면}void값에 도달하여 발신자가 그 값을 사용하려고 하면 동작은 정의되지 않습니다.발신자가 값을 사용하지 않는 한 함수의 끝에서 떨어지는 동작은 올바르게 정의됩니다.

하여 을 할 수 .returnC는 전통적으로 이러한 코드 분석을 위해 컴파일러를 필요로 하지 않습니다.(많은 컴파일러가 해당 분석을 수행하고 필요에 따라 경고를 발행합니다.)

의 수 있는 주요 void(1989년 C 된 버전)에는 K&R C(1989년 ANSI1990년 ISO C 규격 이전)가 없었다.void키워드 또는 타입. C 표준가 암묵적인 C를 있었습니다.int" rule할 수 , "규칙(규칙)"이 을 의미합니다.int★★★★★★ 。

K&R C에서는 결과를 반환하지 않는 함수를 원하는 경우 명시적인 반환 유형 없이 정의하고 값을 반환하지 않습니다.

#include <stdio.h>

do_something() {
    printf("Not returning a value\n");
}

int main() {
    do_something();
    return 0;
}

는 실제로 의 가비지를 합니다.int발신자가 조용히 무시할 수 있는 값입니다.

현대 C에서는 다음과 같이 쓸 수 있습니다.

#include <stdio.h>

void do_something(void) {
    printf("Not returning a value\n");
}

int main(void) {
    do_something();
}

이것에 의해, 발신자는 반환된 값을 사용하지 않게 됩니다.C89/C90의 시점에서는, 이 언어는 기존의 코드의 파손을 회피하기 위해서, 낡은 스타일을 서포트하고 있습니다.암묵적인 경우int의 C99에 요건입니다.을 사용하다void할 수 이후의 암묵적인 C99를 합니다).int오래된 K&R C 코드를 컴파일할 수 있도록 경고와 함께 디폴트로 규칙을 설정합니다).

즉, 가치 반환 기능의 끝에서 흘러내리는 이유(즉, 명시적 없이 종료)return)는 에러가 아닐까요?

첫째, C에서는 함수가 의미 있는 것을 반환하는지 여부가 실행 코드가 반환된 값을 실제로 사용하는 경우에만 중요합니다.아마도 그 언어는 당신이 대부분의 시간 동안 사용하지 않을 것을 알고 있을 때 당신에게 어떤 것도 돌려주도록 강요하고 싶지 않았을 것이다.

둘째, 명백히 언어 사양은 컴파일러 작성자가 명시적인 존재에 대해 가능한 모든 제어 경로를 검출하고 검증하도록 강요하고 싶지 않았다.return(많은 경우, 이것은 그렇게 어려운 일이 아닙니다.또, 일부의 제어 패스에 의해서, 통상 컴파일러가 인식하지 않는 기능인 되돌리지 않는 기능이 생기는 일이 있습니다.이러한 경로는 성가신 false positive의 원인이 될 수 있습니다.

또, C와 C++는, 이 경우의 동작에 대한 정의가 다릅니다.C++에서는 값 반환 함수의 끝에서 흘러내리는 것은 항상 정의되지 않은 동작입니다(함수의 결과가 호출 코드에 의해 사용되는지 여부에 관계없이).C 에서는, 이것에 의해서, 발신자 코드가 반환된 값을 사용하려고 했을 경우에만, 정의되지 않은 동작이 발생합니다.

기본적으로는 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++의 경고이며 일부 경고는 기본적으로 무시되거나 꺼집니다.

레거시 코드(C++도 반환문을 필요로 한 적이 없습니다) 때문이라고 생각합니다.아마도 그 "기능"에 의존하는 거대한 코드 베이스가 있을 것이다.하지만 적어도 거기엔-Werror=return-type많은 컴파일러(gcc 및 clang 포함)에서 플래그를 설정합니다.

C/C++에서는 반환을 주장하는 함수에서 복귀하지 않는 것이 합법입니다.전화 등 다양한 사용 사례가 있습니다.exit(-1)또는 호출하거나 예외를 발생시키는 함수입니다.

컴파일러는 UB로 연결된다고 해도 합법적인 C++를 거부하지 않습니다.특히 경고를 생성하지 않도록 요청하고 있습니다.(GCC는 일부 기능을 기본적으로 켜지만 추가 시 오래된 기능에 대한 새로운 경고가 아니라 새로운 기능에 맞춰져 있는 것 같습니다.)

기본 no-arg gcc를 변경하여 일부 경고를 발생시키는 것은 기존 스크립트 또는 시스템을 만드는 데 방해가 될 수 있습니다.잘 디자인된 것도-Wall경고를 처리하거나 개별 경고를 전환합니다.

C++ 툴 체인 사용법을 배우는 것은 C++ 프로그래머가 되는 것을 배우는 데 장벽이 되지만, C++ 툴 체인은 일반적으로 전문가에 의해 작성됩니다.

일부 제한적이고 드문 경우 값을 반환하지 않고 비포이드 함수의 끝을 흐르는 것이 유용할 수 있습니다.다음의 MSVC 고유의 코드와 같습니다.

double pi()
{
    __asm fldpi
}

이 함수는 x86 어셈블리를 사용하여 pi를 반환합니다.GCC에서의 조립과 달리, 저는 사용하는 방법을 모릅니다.return오버헤드를 수반하지 않고 이 작업을 수행할 수 있습니다.

내가 알기로는 메인스트림 C++ 컴파일러는 잘못된 코드에 대해 최소한 경고를 보내야 합니다.만약 내가 의 몸을 만든다면pi()empty, GCC/Clang은 경고를 보고하고 MSVC는 오류를 보고합니다.

사람들은 예외에 대해 언급했다.exit몇 가지 답변에서.그것들은 타당한 이유가 아니다.예외 발생 또는 호출 중 하나exit에서는 함수 실행이 종료되지 않습니다.그리고 컴파일러들도 알고 있다: 던지기 스테이트먼트를 작성하거나 호출하는 것exit의 빈 몸 속에서pi()는 컴파일러로부터의 경고 또는 오류를 중지합니다.

c99에서는 제약 위반이지만 c89에서는 위반되지 않습니다.대비:

c89:

3.6.6.4 다음의 경우return진술

제약

A return반환 타입이 다음과 같은 함수에는 표현이 있는 문장이 나타나지 않아야 한다.void.

c99:

6.8.6.4 다음 항목에서return진술

제약

A return반환 타입이 다음과 같은 함수에는 표현이 있는 문장이 나타나지 않아야 한다.void.areturn표현 없는 문장은 반환 유형이 다음과 같은 함수에서만 나타납니다.void.

에서조차--std=c99gcc는 경고만 울립니다(단, 추가 활성화는 필요 없음).-W디폴트 또는 c89/90)에서 필요한 플래그를 지정합니다.

편집하여 c89에 추가합니다.}기능을 종료하는 것은 실행과 동등합니다.return(3.6.6.4)단, c99에서는 동작은 정의되어 있지 않습니다(6.9.1).

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

내가 생각할 수 있는 유일한 예외는main()기능, 이 기능에는return(적어도 C++에서는, C규격의 어느쪽도 가지고 있지 않습니다.만약 돌아오지 않으면, 그것은 마치 그 사람이 죽은 것처럼 행동할 것이다.return 0;마지막 스테이트먼트입니다.

이 경고는 명령어 itr = itr -> current Node를 추가하는 것을 잊어버렸기 때문에 발생합니다.기본적으로 이 명령어가 누락되어 함수는 무한 루프 상태가 되어 값을 반환하지 않았습니다.그것이 컴파일 중에 경고를 받은 이유입니다.

void* list_get(list* lst, int idx){

    node* itr = lst->head;
    
    if (idx >= lst->size){
        printf("list out of index");
        exit(1);
    }
    
    while(itr != NULL){
        if(itr->index == idx){
           return  itr->element;
        }
        itr = itr->currentNode;
     
    }


}

컴파일러 경고음을 높여야 할 것 같습니다.

$ 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
$

언급URL : https://stackoverflow.com/questions/1610030/why-does-flowing-off-the-end-of-a-non-void-function-without-returning-a-value-no

반응형