C void 인수“void foo (void)”를 사용하거나“void foo ()”를 사용하지 않는 것이 더 낫습니까? [복제]
이 질문에는 이미 답변이 있습니다.
더 나은 것 : void foo()
또는 void foo(void)
? void가 있으면 추악하고 일관성이 없어 보이지만 그것이 좋다고 들었습니다. 이것이 사실입니까?
편집 : 일부 오래된 컴파일러는 이상한 일을 알고 있지만 GCC 만 사용하면 void foo()
괜찮습니까? 윌 foo(bar);
후 접수?
void foo(void);
이것이 C에서 "매개 변수 없음"이라고 말하는 올바른 방법이며 C ++에서도 작동합니다.
그러나:
void foo();
C와 C ++에서 다른 것을 의미합니다! C에서는 "알 수없는 유형의 매개 변수를 여러 개 사용할 수 있음"을 의미하고 C ++에서는와 동일 함을 의미합니다 foo(void)
.
변수 인수 목록 함수는 본질적으로 형식이 안전하지 않으므로 가능한 경우 피해야합니다.
C에서 매개 변수를 지정하는 두 가지 방법이 있습니다. 하나는 식별자 목록을 사용하고 다른 하나는 매개 변수 유형 목록을 사용합니다. 식별자 목록은 생략 할 수 있지만 유형 목록은 생략 할 수 있습니다. 따라서 함수 정의에서 하나의 함수가 인수를 사용하지 않는다고 말하면 (생략 된) 식별자 목록 으로이 작업을 수행합니다.
void f() {
/* do something ... */
}
그리고 이것은 매개 변수 유형 목록으로
void f(void) {
/* do something ... */
}
매개 변수 유형 목록에서 하나의 매개 변수 유형 만 void 인 경우 (이름이 없어야 함) 함수가 인수를 사용하지 않음을 의미합니다. 그러나 함수를 정의하는 두 가지 방법은 선언하는 것과 관련하여 차이가 있습니다.
식별자 목록
첫 번째는 함수가 특정 수의 인수를 취하지 만 식별자 목록을 사용하는 모든 함수 선언과 같이 카운트가 전달되거나 필요한 유형이 없음을 정의합니다. 따라서 호출자는 미리 유형과 개수를 정확하게 알아야합니다. 따라서 호출자가 인수를 제공하는 함수를 호출하면 동작이 정의되지 않습니다. 예를 들어 호출 된 함수가 제어권을 얻을 때 다른 레이아웃을 기대하기 때문에 스택이 손상 될 수 있습니다.
함수 매개 변수에서 식별자 목록을 사용하는 것은 더 이상 사용되지 않습니다. 그것은 옛날에 사용되었으며 여전히 많은 생산 코드에 있습니다. 인수 승격으로 인해 심각한 위험을 초래할 수 있습니다 (승격 된 인수 유형이 함수 정의의 매개 변수 유형과 일치하지 않으면 동작도 정의되지 않습니다!). 따라서 항상 void
선언과 함수 정의 모두에서 매개 변수가없는 함수에 대해서는 것을 사용하십시오 .
매개 변수 유형 목록
두 번째는 함수가 인수 0을 취하지 않고 매개 변수 유형 목록 ()을 사용하여 함수가 선언 된 모든 경우와 마찬가지로이를 전달 함을 정의합니다 prototype
. 호출자가 함수를 호출하고 인수를 제공하면 오류이며 컴파일러는 적절한 오류를 내 보냅니다.
함수를 선언하는 두 번째 방법에는 많은 이점이 있습니다. 물론 양과 유형의 매개 변수를 확인하는 것입니다. 또 다른 차이점은 컴파일러가 매개 변수 유형을 알고 있기 때문에 인수의 암시 적 변환을 매개 변수 유형에 적용 할 수 있다는 것입니다. 매개 변수 유형 목록이 없으면 수행 할 수 없으며 인수는 승격 된 유형 (기본 인수 승격이라고 함)으로 변환됩니다. char
될 것이다 int
, 예를 들어, 동안이 float
될 것입니다 double
.
함수의 복합 타입
그런데 파일에 생략 된 식별자 목록과 매개 변수 유형 목록이 모두 포함되어 있으면 매개 변수 유형 목록이 "승리"됩니다. 마지막 함수 유형에는 프로토 타입이 포함됩니다.
void f();
void f(int a) {
printf("%d", a);
}
// f has now a prototype.
두 선언 모두 모순되는 말이 없기 때문입니다. 그러나 두 번째는 또한 할 말이 있습니다. 하나의 주장이 받아 들여집니다. 반대로 할 수도 있습니다
void f(a)
int a;
{
printf("%d", a);
}
void f(int);
첫 번째는 식별자 목록을 사용하여 함수를 정의하고 두 번째는 매개 변수 유형 목록을 포함하는 선언을 사용하여 프로토 타입을 제공합니다.
void foo(void)
매개 변수가 허용되지 않습니다.
void foo()
적어도 (컴파일러가 아닌) 함수의 선언 인 경우 (일부 컴파일러에서) 매개 변수를 보낼 수 있음을 의미합니다.
C99 인용구
이 답변은 C99 N1256 표준 초안 의 관련 부분을 인용하고 설명하는 것을 목표로합니다 .
선언자 정의
선언 자라는 용어 가 많이 나올 것이므로 이해해 봅시다.
From the language grammar, we find that the following underline characters are declarators:
int f(int x, int y);
^^^^^^^^^^^^^^^
int f(int x, int y) { return x + y; }
^^^^^^^^^^^^^^^
int f();
^^^
int f(x, y) int x; int y; { return x + y; }
^^^^^^^
Declarators are part of both function declarations and definitions.
There are 2 types of declarators:
- parameter type list
- identifier list
Parameter type list
Declarations look like:
int f(int x, int y);
Definitions look like:
int f(int x, int y) { return x + y; }
It is called parameter type list because we must give the type of each parameter.
Identifier list
Definitions look like:
int f(x, y)
int x;
int y;
{ return x + y; }
Declarations look like:
int g();
We cannot declare a function with a non-empty identifier list:
int g(x, y);
because 6.7.5.3 "Function declarators (including prototypes)" says:
3 An identifier list in a function declarator that is not part of a definition of that function shall be empty.
It is called identifier list because we only give the identifiers x
and y
on f(x, y)
, types come after.
This is an older method, and shouldn't be used anymore. 6.11.6 Function declarators says:
1 The use of function declarators with empty parentheses (not prototype-format parameter type declarators) is an obsolescent feature.
and the Introduction explains what is an obsolescent feature:
Certain features are obsolescent, which means that they may be considered for withdrawal in future revisions of this International Standard. They are retained because of their widespread use, but their use in new implementations (for implementation features) or new programs (for language [6.11] or library features [7.26]) is discouraged
f() vs f(void) for declarations
When you write just:
void f();
it is necessarily an identifier list declaration, because 6.7.5 "Declarators" says defines the grammar as:
direct-declarator:
[...]
direct-declarator ( parameter-type-list )
direct-declarator ( identifier-list_opt )
so only the identifier-list version can be empty because it is optional (_opt
).
direct-declarator
is the only grammar node that defines the parenthesis (...)
part of the declarator.
So how do we disambiguate and use the better parameter type list without parameters? 6.7.5.3 Function declarators (including prototypes) says:
10 The special case of an unnamed parameter of type void as the only item in the list specifies that the function has no parameters.
So:
void f(void);
is the way.
This is a magic syntax explicitly allowed, since we cannot use a void
type argument in any other way:
void f(void v);
void f(int i, void);
void f(void, int);
What can happen if I use an f() declaration?
Maybe the code will compile just fine: 6.7.5.3 Function declarators (including prototypes):
14 The empty list in a function declarator that is not part of a definition of that function specifies that no information about the number or types of the parameters is supplied.
So you can get away with:
void f();
void f(int x) {}
Other times, UB can creep up (and if you are lucky the compiler will tell you), and you will have a hard time figuring out why:
void f();
void f(float x) {}
See: Why does an empty declaration work for definitions with int arguments but not for float arguments?
f() and f(void) for definitions
f() {}
vs
f(void) {}
are similar, but not identical.
6.7.5.3 Function declarators (including prototypes) says:
14 An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters.
which looks similar to the description of f(void)
.
But still... it seems that:
int f() { return 0; }
int main(void) { f(1); }
is conforming undefined behavior, while:
int f(void) { return 0; }
int main(void) { f(1); }
is non conforming as discussed at: Why does gcc allow arguments to be passed to a function defined to be with no arguments?
TODO understand exactly why. Has to do with being a prototype or not. Define prototype.
Besides syntactical differences, many people also prefer using void function(void)
for pracitical reasons:
If you're using the search function and want to find the implementation of the function, you can search for function(void)
, and it will return the prototype as well as the implementation.
If you omitted the second void
, you have to search for function()
and will therefore also find all function calls, making it difficulter to find the actual implementation.
In C++, there is no difference in main()
and main(void)
.
But in C, main()
will be called with any number of parameters.
Example:
main ( ){
main(10,"abc",12.28);
//Works fine !
//It won't give the error. The code will compile successfully.
//(May cause Segmentation fault when run)
}
main(void)
will be called without any parameters. If we try to pass then this end up leading to a compiler error.
Example:
main (void) {
main(10,"abc",12.13);
//This throws "error: too many arguments to function ‘main’ "
}
'Programing' 카테고리의 다른 글
@ 미디어 최소 너비 및 최대 너비 (0) | 2020.05.09 |
---|---|
Java VM이 몇 개의 스레드를 지원할 수 있습니까? (0) | 2020.05.09 |
Swift에서 사전을 반복 (0) | 2020.05.09 |
정규 표현식을 허용하는 JavaScript의 String.indexOf () 버전이 있습니까? (0) | 2020.05.09 |
지역 지점에서 다른 지점으로 "당기는"방법은 무엇입니까? (0) | 2020.05.09 |