매개 변수가없는 함수 (실제 함수 정의와 비교하여)가 컴파일되는 이유는 무엇입니까?
방금 컴파일하는 이유에 대해 혼란스러워하는 누군가의 C 코드를 발견했습니다. 이해할 수없는 두 가지 사항이 있습니다.
첫째, 함수 프로토 타입에는 실제 함수 정의에 비해 매개 변수가 없습니다. 둘째, 함수 정의의 매개 변수에 유형이 없습니다.
#include <stdio.h>
int func();
int func(param)
{
return param;
}
int main()
{
int bla = func(10);
printf("%d", bla);
}
왜 이것이 작동합니까? 몇 개의 컴파일러에서 테스트했으며 정상적으로 작동합니다.
다른 모든 답변은 정확하지만 완료를 위해
함수는 다음과 같은 방식으로 선언됩니다.
return-type function-name(parameter-list,...) { body... }
return-type 은 함수가 반환하는 변수 유형입니다. 배열 유형 또는 함수 유형이 될 수 없습니다. 지정하지 않으면 int로 간주 됩니다.
function-name 은 함수의 이름 입니다.
parameter-list 는 함수가 쉼표로 구분하여 취하는 매개 변수 목록입니다. 매개 변수가 제공되지 않으면 함수는 사용하지 않으며 빈 괄호 세트 또는 키워드 void를 사용하여 정의해야합니다. 매개 변수 목록에서 변수 앞에 변수 유형이 없으면 int로 간주 됩니다. 배열과 함수는 함수로 전달되지 않지만 포인터로 자동 변환됩니다. 줄임표 (, ...)로 목록이 종료되면 설정된 수의 매개 변수가 없습니다. 참고 : 생략 부호를 사용할 때 헤더 stdarg.h를 사용하여 인수에 액세스 할 수 있습니다.
그리고 완전성을 위해 다시. C11 사양 6 : 11 : 6부터 (페이지 : 179)
빈 괄호 (prototype 형식 매개 변수 유형 선언자가 아님) 와 함께 함수 선언자를 사용하는 것은 더 이상 사용 되지 않는 기능 입니다.
C func()
에서 당신은 많은 수의 인수를 전달할 수 있습니다. 인수를 원하지 않으면로 선언해야 func(void)
합니다. 지정되지 않은 경우 함수에 전달하는 유형의 기본값은 int
입니다.
int func();
는 C 표준이없는 날, 즉 K & R C 의 날 (1989 년 이전에 첫 번째 "ANSI C"표준이 출판 된 해) 부터 사용되지 않는 함수 선언입니다 .
K & R C에는 프로토 타입 이 없었 으며 키워드 void
는 아직 발명되지 않았습니다. 컴파일러에게 함수 의 리턴 유형 에 대해 알리는 것만으로도 충분 합니다. K & R C의 빈 매개 변수 목록은 "지정되지 않았지만 고정 된"수의 인수를 의미합니다. 당신이 가진 함수를 호출해야 함을 의미합니다 고정 같은 인수의 수 (로 반대마다 가변 같은 기능 printf
수와 종류는 각각의 호출에 따라 다를 수 있습니다).
많은 컴파일러가이 구문을 진단합니다. 특히 gcc -Wstrict-prototypes
"함수 선언은 프로토 타입이 아닙니다"라고 말할 것입니다. 프로토 타입 처럼 보이지만 (특히 C ++에 중독 된 경우) 그렇지 않습니다. 구식 K & R C 반환 형식 선언입니다.
경험 법칙 : 빈 매개 변수 목록 선언을 비워 두지 마십시오 int func(void)
. 구체적으로 사용하십시오. 이것은 K & R 리턴 타입 선언을 적절한 C89 프로토 타입으로 바꿉니다. 컴파일러는 행복하고 개발자는 행복하며 정적 검사기는 행복합니다. C ++의 ^ W ^ Wfond가 오해 한 사람들은 외국 언어 기술을 연습하려고 할 때 추가 문자를 입력해야하기 때문에 울 수도 있습니다.
- 빈 매개 변수 목록은 "모든 인수"를 의미하므로 정의가 잘못되지 않았습니다.
- 누락 된 유형은로 가정됩니다
int
.
나는 이것을 통과하는 모든 빌드가 구성된 경고 / 오류 수준에서 부족하다고 생각할 것입니다. 실제 코드를 허용하는 것은 의미가 없습니다.
그것은의 K & R 스타일 함수 선언 및 정의. C99 표준 (ISO / IEC 9899 : TC3)에서
섹션 6.7.5.3 함수 선언자 (시제품 포함)
식별자 목록은 함수 매개 변수의 식별자 만 선언합니다. 해당 함수 정의의 일부인 함수 선언자의 빈 목록은 함수에 매개 변수가 없음을 지정합니다. 해당 함수의 정의에 포함되지 않은 함수 선언자의 빈 목록은 매개 변수의 수 또는 유형에 대한 정보가 제공되지 않도록 지정합니다. 두 함수 유형이 모두 "이전 스타일"인 경우 매개 변수 유형이 비교되지 않습니다.
6.11.6 함수 선언자
프로토 타입 형식 매개 변수 유형 선언자가 아닌 빈 괄호와 함께 함수 선언자를 사용하는 것은 더 이상 사용되지 않는 기능입니다.
6.11.7 절 정의
별도의 매개 변수 식별자 및 선언 목록 (프로토 타입 형식 매개 변수 유형 및 식별자 선언자가 아님)과 함께 함수 정의를 사용하는 것은 더 이상 사용되지 않는 기능입니다.
이전 스타일은 K & R 스타일을 의미합니다.
예:
선언: int old_style();
정의:
int old_style(a, b)
int a;
int b;
{
/* something to do */
}
C는 int
함수 반환 형식 및 매개 변수 목록에 형식이없는 것으로 가정 합니다 . 이 규칙에 대해서만 이상한 일이 가능합니다.
함수 정의는 다음과 같습니다.
int func(int param) { /* body */}
프로토 타입이라면
int func(int param);
프로토 타입에서는 매개 변수 유형 만 지정할 수 있습니다. 매개 변수 이름은 필수가 아닙니다. 그래서
int func(int);
또한 매개 변수 유형을 지정하지 않지만 이름 int
은 유형으로 가정됩니다.
int func(param);
더 멀리 가면 다음도 작동합니다.
func();
컴파일러는 int func()
쓸 때를 가정합니다 func()
. 그러나 func()
함수 본문 안에 넣지 마십시오 . 그것은 함수 호출입니다
@Krishnabhadra에서 언급했듯이 다른 사용자의 모든 이전 응답은 올바르게 해석되었으며 일부 요점을보다 자세하게 분석하려고합니다.
ANSI-C에서와 같이 Old-C에서 " untyped formal parameter "는 8 비트 MPU에서 작업 레지스터 또는 명령어 깊이 기능 (그림자 레지스터 또는 명령어 누적주기)의 차원을 취하면 16 비트에서 int16이됩니다. 64 비트 아키텍처가 다음과 같은 옵션을 컴파일하도록 선택할 수 있습니다.
높은 수준에서 구현이 더 단순 해 보이지만 여러 매개 변수를 전달하려면 제어 차원 데이터 유형 단계에서 프로그래머의 작업이 더 까다로워집니다.
다른 경우, 일부 마이크로 프로세서 아키텍처의 경우, 사용자 정의 된 ANSI 컴파일러는이 오래된 기능 중 일부를 사용하여 코드 사용을 최적화하여 이러한 "유형화되지 않은 형식 매개 변수"의 위치를 작업 레지스터 내부 또는 외부에서 작동하도록합니다. "volatile"및 "register"를 사용하는 것과 거의 동일합니다.
그러나 가장 현대적인 컴파일러는 두 가지 유형의 매개 변수 선언을 구분하지 않습니다.
리눅스에서 gcc를 사용한 컴파일의 예 :
In any case the statement of the prototype locally is of no use, because there is no call without parameters reference to this prototype will be remiss. If you use the system with "untyped formal parameter", for an external call, proceed to generate a declarative prototype data type.
Like this:
int myfunc(int param);
Regarding parameter type, there are already correct answers here but if you want to hear it from the compiler you can try adding some flags (flags are almost always a good idea anyways).
compiling your program using gcc foo.c -Wextra
I get:
foo.c: In function ‘func’:
foo.c:5:5: warning: type of ‘param’ defaults to ‘int’ [-Wmissing-parameter-type]
strangely -Wextra
doesn't catch this for clang
(it doesn't recognize -Wmissing-parameter-type
for some reason, maybe for historical ones mentioned above) but -pedantic
does:
foo.c:5:10: warning: parameter 'param' was not declared,
defaulting to type 'int' [-pedantic]
int func(param)
^
1 warning generated.
And for prototype issue as said again above int func()
refers to arbitrary parameters unless you exclicitly define it as int func(void)
which would then give you the errors as expected:
foo.c: In function ‘func’:
foo.c:6:1: error: number of arguments doesn’t match prototype
foo.c:3:5: error: prototype declaration
foo.c: In function ‘main’:
foo.c:12:5: error: too many arguments to function ‘func’
foo.c:5:5: note: declared here
or in clang
as:
foo.c:5:5: error: conflicting types for 'func'
int func(param)
^
foo.c:3:5: note: previous declaration is here
int func(void);
^
foo.c:12:20: error: too many arguments to function call, expected 0, have 1
int bla = func(10);
~~~~ ^~
foo.c:3:1: note: 'func' declared here
int func(void);
^
2 errors generated.
If the function declaration has no parameters i.e. empty then it is taking unspecified number of arguments. If you want to make it take no arguments then change it to:
int func(void);
This is why I typically advise people to compile their code with:
cc -Wmissing-variable-declarations -Wstrict-variable-declarations -Wold-style-definition
These flags enforce a couple of things:
- -Wmissing-variable-declarations: It is impossible to declare a non-static function without getting a prototype first. This makes it more likely that a prototype in a header file matches with the actual definition. Alternatively, it enforces that you add the static keyword to functions that don't need to be visible publicly.
- -가변 변수 선언 : 프로토 타입이 인수를 올바르게 나열해야합니다.
- -Wold-style-definition : 함수 정의 자체도 인수를 올바르게 나열해야합니다.
이 플래그는 기본적으로 많은 오픈 소스 프로젝트에서 사용됩니다. 예를 들어, FreeBSD는 Makefile에서 WARNS = 6으로 빌드 할 때이 플래그들을 활성화합니다.
'Programing' 카테고리의 다른 글
IIS AppPoolIdentity 및 파일 시스템 쓰기 액세스 권한 (0) | 2020.02.25 |
---|---|
로그 아웃 : GET 또는 POST? (0) | 2020.02.25 |
생성기 표현 대 목록 이해 (0) | 2020.02.25 |
Java에서 코어 수 찾기 (0) | 2020.02.25 |
당신은 어떻게 사용합니까? (0) | 2020.02.25 |