programing

gcc는 인수 없이 정의된 함수에 인수를 전달할 수 있도록 하는 이유는 무엇입니까?

itsource 2023. 1. 27. 21:51
반응형

gcc는 인수 없이 정의된 함수에 인수를 전달할 수 있도록 하는 이유는 무엇입니까?

왜 이 코드가 컴파일되는지 모르겠어요.

#include <stdio.h>
void foo() {
    printf("Hello\n");
}

int main() {
    const char *str = "bar";
    foo(str);
    return 0;
}

gcc는 foo()에 너무 많은 인수를 전달하고 있다는 경고도 하지 않습니다.이것은 예상된 동작입니까?

C에서 빈 파라미터 리스트로 선언된 함수는 호출 시 임의의 수의 인수를 받아들입니다.이러한 인수는 통상적인 산술 프로모션에 따릅니다.제공된 인수가 함수의 정의에 적합한지 확인하는 것은 호출자의 책임입니다.

인수를 하려면 0으로 선언해야 .void foo(void);.

이는 역사적 이유로, 원래 C 기능에는 시제품이 없었습니다. 왜냐하면 C는 활자가 없는 언어인 B에서 발전했기 때문입니다.프로토타입이 추가되었을 때 원래 무형 선언문은 하위 호환성을 위해 언어로 남겨졌습니다.

빈 파라미터 목록에 대해 gcc가 경고하도록 하려면 다음 명령을 사용합니다.

인수 유형을 지정하지 않고 함수가 선언되거나 정의된 경우 경고합니다.(인수 유형을 지정하는 선언이 선행되는 경우 오래된 스타일의 함수 정의는 경고 없이 허용됩니다).

이유로()파라미터 목록의 경우 기본적으로 "함수가 호출될 때 파라미터를 파악한다"를 의미합니다. 것을 하려면 , 「」를 합니다.(void).

편집: 이 문제에서 나이가 많다는 평판을 얻고 있는 것 같습니다.예전엔 프로그래밍이 어땠는지 알려드리기 위해, 여기 제 첫 번째 프로그램이 있습니다.(C가 아닙니다.그 전에 어떤 작업을 해야 했는지 보여 줍니다).

void foo() {
    printf("Hello\n");
}

foo(str);

되어 있는 ).void foo(void) {/*...*/}또한 제약 위반이 없으므로 컴파일러는 진단 프로그램을 발행할 필요가 없습니다.

그러나 이 프로그램은 다음 C 규칙에 따라 동작을 정의하지 않았습니다.

송신원:

(C99, 6.9.1p7) "declarator에 파라미터 타입 리스트가 포함되어 있는 경우 리스트에는 모든 파라미터 타입도 지정됩니다.이러한 declarator는 같은 변환 유닛 내의 같은 함수에 대한 이후 호출의 함수 프로토타입으로도 기능합니다.선언자가 식별자 리스트를 포함할 경우 (142) 파라미터의 종류를 다음 선언 리스트에 선언해야 한다.

foo기능은 프로토타입을 제공하지 않습니다.

송신원:

(C99, 6.5.2p6) "호출된 함수를 나타내는 식에 프로토타입을 포함하지 않는 유형이 있는 경우 [...] 인수 수가 매개 변수 수와 같지 않으면 동작은 정의되지 않습니다."

foo(str)이치노

C는 정의되지 않은 동작을 호출하는 프로그램에 대한 진단을 실행하도록 구현에 명령하지 않지만 프로그램은 여전히 잘못된 프로그램입니다.

C99 표준(6.7.5.3)과 C11 표준(6.7.6.3)은 모두 다음과 같이 기술되어 있다.

식별자 리스트는 함수 파라미터의 식별자만을 선언합니다.함수 정의의 일부인 함수 선언자의 빈 목록은 함수에 매개 변수가 없음을 나타냅니다.함수 정의의 일부가 아닌 함수 선언자의 빈 목록은 매개 변수의 수 또는 유형에 대한 정보를 제공하지 않도록 지정합니다.

foo 선언은 정의의 일부이기 때문에 선언에서는 foo가 0 인수를 받아들이도록 지정되어 있기 때문에 콜 foo(str)는 적어도 도덕적으로 잘못되어 있습니다.단, 아래에 기술한 바와 같이 C에는 '잘못'의 정도가 다르기 때문에 컴파일러는 어떤 종류의 '잘못'에 대처하는 방법이 다를 수 있습니다.

조금 더 간단한 예를 들자면, 다음 프로그램을 고려해 보겠습니다.

int f() { return 9; }
int main() {
  return f(1);
}

Clang을 사용하여 위의 내용을 컴파일하면 다음과 같습니다.

tmp$ cc tmp3.c
tmp3.c:4:13: warning: too many arguments in call to 'f'
  return f(1);
         ~  ^
1 warning generated.

gcc 4.8로 컴파일을 하면 -Wall을 사용해도 오류나 경고가 발생하지 않습니다.이전 답변에서는 f의 정의가 프로토타입이 아니라고 올바르게 보고하는 -Wstrict-protype을 사용할 것을 제안했지만, 이것이 요점은 아닙니다.C 표준은 위와 같은 비프로토타입 형식의 함수 정의를 허용하며, 이 정의는 함수가 0 인수를 받는 것을 명시하고 있다.

이제 제약이 있습니다(C11조 6.5.2항).

호출된 함수를 나타내는 식이 프로토타입을 포함하는 유형을 갖는 경우, 인수 수는 매개변수의 수와 일치해야 한다.

그러나 이 경우 함수 유형에 프로토타입이 포함되어 있지 않기 때문에 이 제약조건은 적용되지 않습니다.그러나 여기에 적용되는 의미론 섹션('제약'이 아님)의 후속 문장이 있습니다.

호출된 함수를 나타내는 식에 프로토타입을 포함하지 않는 유형이 있는 경우...인수 수가 매개 변수 수와 같지 않으면 동작은 정의되지 않습니다.

따라서 함수 호출은 정의되지 않은 동작을 초래합니다(즉, 프로그램이 "엄밀하게 준수"되지 않습니다).그러나 이 기준서는 실제 제약조건을 위반한 경우에만 진단메시지를 보고하도록 요구하고 있으며, 이 경우 제약조건을 위반하지 않는다.따라서 gcc는 "적합한 구현"이 되기 위해 오류 또는 경고를 보고할 필요가 없습니다.

그래서 왜 gcc가 그것을 허용하는가라는 질문에 대한 답은 gcc는 제약 위반이 아니기 때문에 아무것도 보고할 필요가 없다는 것입니다.또한 gcc는 -Wall 또는 -Wpedantic을 사용하더라도 정의되지 않은 모든 동작을 보고한다고 주장하지 않습니다.이것은 정의되지 않은 동작입니다.즉, 실장에서는 처리 방법을 선택할 수 있으며, gcc는 경고 없이 컴파일을 선택했습니다(인수는 무시합니다).

언급URL : https://stackoverflow.com/questions/12643202/why-does-gcc-allow-arguments-to-be-passed-to-a-function-defined-to-be-with-no-ar

반응형