C void 인수 "void foo (void)"를 사용하는 것이 낫습니까? [복제하다

StackOverflow https://stackoverflow.com/questions/693788

  •  22-08-2019
  •  | 
  •  

문제

이 질문은 이미 여기에 답이 있습니다.

더 좋은 점 : void foo() 또는 void foo(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 함수의 정의와 함수의 정의에서 매개 변수가없는 함수에 대한 것입니다.

매개 변수 유형 목록

두 번째는 함수가 제로 인수를 가져 와서 전달되는 것을 정의하고이를 전달합니다. 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 표준 초안.

선언자의 정의

용어 선언자 많이 올 것입니다. 이해합시다.

언어 문법에서 우리는 다음과 같은 밑줄 문자가 선언자임을 알게됩니다.

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; }
    ^^^^^^^

선언자는 기능 선언과 정의의 일부입니다.

선언자에는 두 가지 유형이 있습니다.

  • 매개 변수 유형 목록
  • 식별자 목록

매개 변수 유형 목록

선언은 다음과 같습니다.

int f(int x, int y);

정의는 다음과 같습니다.

int f(int x, int y) { return x + y; }

각 매개 변수의 유형을 제공해야하므로 매개 변수 유형 목록이라고합니다.

식별자 목록

정의는 다음과 같습니다.

int f(x, y)
    int x;
    int y;
{ return x + y; }

선언은 다음과 같습니다.

int g();

비어 있지 않은 식별자 목록이있는 함수를 선언 할 수 없습니다.

int g(x, y);

왜냐하면 6.7.5.3 "기능 선언자 (프로토 타입 포함)" 말 :

3 해당 함수의 정의의 일부가 아닌 함수 선언자의 식별자 목록은 비어 있어야합니다.

식별자 만 제공하기 때문에 식별자 목록이라고합니다. x 그리고 y ~에 f(x, y), 유형은 뒤 따릅니다.

이것은 오래된 방법이며 더 이상 사용해서는 안됩니다. 6.11.6 기능 선언자 말 :

1 빈 괄호 (프로토 타입 형식 매개 변수 유형 선언자가 아님)가있는 기능 선언자의 사용은 노란 기능입니다.

그리고 소개 AN이 무엇인지 설명합니다 노아용 특징:

특정 특징은 불분명 한 것이므로이 국제 표준의 향후 개정에서 철수로 간주 될 수 있음을 의미합니다. 그들은 광범위한 사용으로 인해 유지되지만 새로운 구현 (구현 기능) 또는 새로운 프로그램 (언어 [6.11] 또는 라이브러리 기능 [7.26])에서의 사용에 대한 사용은 권장되지 않습니다.

f () vs f (void) 선언에 대한

당신이 그냥 쓸 때 :

void f();

반드시 식별자 목록 선언입니다 6.7.5 "선언자" 문법을 다음과 같이 정의합니다.

direct-declarator:
    [...]
    direct-declarator ( parameter-type-list )
    direct-declarator ( identifier-list_opt )

따라서 식별자 목록 버전 만 선택 사항이므로 비어있을 수 있습니다 (_opt).

direct-declarator 괄호를 정의하는 유일한 문법 노드입니다 (...) 선언자의 일부.

그렇다면 매개 변수없이 더 나은 매개 변수 유형 목록을 어떻게 명확하게하고 사용합니까? 6.7.5.3 기능 선언자 (프로토 타입 포함) 말 :

10 유형 void의 이름이없는 매개 변수의 특수한 경우 목록의 유일한 항목은 함수에 매개 변수가 없음을 지정합니다.

그래서:

void f(void);

방법입니다.

이것은 우리가 사용할 수 없기 때문에 명시 적으로 허용되는 마술 구문입니다. void 다른 방식으로 인수를 입력하십시오.

void f(void v);
void f(int i, void);
void f(void, int);

f () 선언을 사용하면 어떻게 될 수 있습니까?

코드가 잘 컴파일 될 수 있습니다. 6.7.5.3 기능 선언자 (프로토 타입 포함):

14 해당 함수의 정의의 일부가 아닌 함수 선언자의 빈 목록은 매개 변수의 수 또는 유형에 대한 정보가 제공되지 않음을 지정합니다.

그래서 당신은 다음과 같이 도망 갈 수 있습니다.

void f();
void f(int x) {}

다른 경우에는 UB가 기어 올릴 수 있습니다 (운이 좋으면 컴파일러가 말해 줄 것입니다).

void f();
void f(float x) {}

보다: 빈 선언은 왜 int 인수가있는 정의에 효과가 있지만 플로트 인수에 대해서는 작동하지 않습니까?

정의에 대한 f () 및 f (void)

f() {}

vs

f(void) {}

비슷하지만 동일하지는 않습니다.

6.7.5.3 기능 선언자 (프로토 타입 포함) 말 :

14 해당 함수의 정의의 일부인 함수 선언자의 빈 목록은 함수에 매개 변수가 없음을 지정합니다.

설명과 비슷해 보입니다 f(void).

하지만 아직... 그것은 다음과 같습니다.

int f() { return 0; }
int main(void) { f(1); }

정의되지 않은 행동을 준수하는 동안 :

int f(void) { return 0; }
int main(void) { f(1); }

다음과 같이 논의 된 바와 같이 일치하지 않습니다. GCC가 인수가 인수가없는 것으로 정의 된 함수로 인수를 전달할 수있는 이유는 무엇입니까?

THODO는 이유를 정확하게 이해합니다. 프로토 타입이 아닌 것과 관련이 있습니다. 프로토 타입을 정의하십시오.

구문 적 차이 외에도 많은 사람들이 사용하는 것을 선호합니다 void function(void) 실습 적 이유 :

검색 기능을 사용하고 있고 기능의 구현을 찾으려면 검색 할 수 있습니다. function(void), 그리고 구현뿐만 아니라 프로토 타입을 반환합니다.

두 번째를 생략하면 void, 당신은 검색해야합니다 function() 따라서 모든 기능 호출을 찾아 실제 구현을 찾기가 어려워집니다.

C ++에는 있습니다 아니요 차이 main() 그리고 main(void).

하지만 C, main() 함께 호출됩니다 어느 매개 변수 수.

예시:

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) 호출됩니다 없이 모든 매개 변수. 우리가 통과하려고하면 이로 인해 컴파일러 오류가 발생합니다.

예시:

main (void) {
     main(10,"abc",12.13);
     //This throws "error: too many arguments to function ‘main’ "
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top