gcc에서 인수가없는 것으로 정의 된 함수에 인수를 전달할 수있는 이유는 무엇입니까?
이 코드가 컴파일되는 이유를 모르겠습니다.
#include <stdio.h>
void foo() {
printf("Hello\n");
}
int main() {
const char *str = "bar";
foo(str);
return 0;
}
gcc는 foo ()에 너무 많은 인수를 전달하고 있다는 경고도 표시하지 않습니다. 예상되는 동작입니까?
C에서 빈 매개 변수 목록으로 선언 된 함수는 호출 될 때 임의의 수의 인수를 허용하며 이는 일반적인 산술 승격에 따릅니다. 제공된 인수가 함수 정의에 적합한 지 확인하는 것은 호출자의 책임입니다.
인수가없는 함수를 선언하려면 void foo(void);.
이것은 역사적인 이유 때문입니다. 원래 C 함수는 유형 이없는 언어 인 B 에서 진화했기 때문에 프로토 타입이 없었습니다 . 프로토 타입이 추가되었을 때 이전 버전과의 호환성을 위해 원래 유형없는 선언이 언어로 남겨졌습니다.
gcc가 빈 매개 변수 목록에 대해 경고하도록하려면 -Wstrict-prototypes다음을 사용하십시오 .
인수 유형을 지정하지 않고 함수가 선언되거나 정의되면 경고합니다. (인수 유형을 지정하는 선언이 선행하는 경우 경고없이 이전 스타일의 함수 정의가 허용됩니다.)
레거시 이유로, ()매개 변수 목록에 대해 함수를 선언하는 것은 본질적으로 "함수가 호출 될 때 매개 변수를 파악"하는 것을 의미합니다. 함수에 매개 변수가 없도록 지정하려면을 사용하십시오 (void).
편집 : 나는이 문제에서 늙어서 명성을 쌓고 있다고 느낍니다. 아이들이 예전에 프로그래밍이 어떤 것인지 알 수 있도록 여기에 제 첫 번째 프로그램이 있습니다. (C가 아닙니다. 이전에 작업해야했던 작업을 보여줍니다.)
void foo() {
printf("Hello\n");
}
foo(str);
C에서이 코드는 제약 조건을 위반하지 않으며 (로 프로토 타입 형식에 정의 된 경우 void foo(void) {/*...*/}) 제약 조건 위반이 없으므로 컴파일러에서 진단을 실행할 필요가 없습니다.
그러나이 프로그램에는 다음 C 규칙에 따라 정의되지 않은 동작이 있습니다.
에서:
(C99, 6.9.1p7) "선언자가 매개 변수 유형 목록을 포함하는 경우 목록은 모든 매개 변수의 유형도 지정합니다. 이러한 선언자는 나중에 동일한 번역 단위에서 동일한 함수에 대한 호출을위한 함수 프로토 타입 역할도합니다. 선언자가 식별자 목록을 포함하는 경우 142) 매개 변수 유형은 다음 선언 목록에 선언되어야합니다. "
foo함수는 프로토 타입을 제공하지 않습니다.
에서:
(C99, 6.5.2.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-prototypes 사용을 제안했지만 실제로는 중요하지 않습니다. C 표준은 위의 것과 같은 비 프로토 타입 형식의 함수 정의를 허용하며 표준은이 정의가 함수가 0 인수를 취하도록 지정한다고 명시합니다.
Now there is a constraint (C11 Sec. 6.5.2.2):
If the expression that denotes the called function has a type that includes a prototype, the number of arguments shall agree with the number of parameters.
However, this constraint does not apply in this case, since the type of the function does not include a prototype. But here is a subsequent statement in the semantics section (not a "constraint"), that does apply:
If the expression that denotes the called function has a type that does not include a prototype ... If the number of arguments does not equal the number of parameters, the behavior is undefined.
Hence the function call does result in undefined behavior (i.e., the program is not "strictly conforming"). However, the Standard only requires an implementation to report a diagnostic message when an actual constraint is violated, and in this case, there is no violation of a constraint. Hence gcc is not required to report an error or warning in order to be a "conforming implementation".
So I think the answer to the question, why does gcc allow it?, is that gcc is not required to report anything, since this is not a constraint violation. Moreover gcc does not claim to report every kind of undefined behavior, even with -Wall or -Wpedantic. It is undefined behavior, which means the implementation can choose how to deal with it, and gcc has chosen to compile it without warnings (and apparently it just ignores the argument).
'Program Club' 카테고리의 다른 글
| Vim-선택한 범위의 행 수 (0) | 2020.10.23 |
|---|---|
| C에서 nanosleep ()을 사용하는 방법? (0) | 2020.10.23 |
| C #의 위도 / 경도 값에 대한 이중 또는 소수 (0) | 2020.10.23 |
| AndroidManifest xml 파일에서 android : supportsRtl =“true”사용은 무엇입니까? (0) | 2020.10.23 |
| POSIX 시스템에서 argc가 0이 될 수 있습니까? (0) | 2020.10.23 |