source

C99의 func()와 func(void)의 비교

factcode 2022. 8. 13. 12:07
반응형

C99의 func()와 func(void)의 비교

void func()

실제로 빈 파라미터는 모든 인수가 허용됨을 의미합니다.

void func(void)는 인수를 받지 않습니다.

그러나 Standard C99에는 다음과 같은 행이 있습니다.

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

★★★★★★★★★★★★★★★★★★★★★★★.func() ★★★★★★★★★★★★★★★★★」func(void)★★★★★★★★★★★★★★★★★★?

TL;DR

선언문에서

void func1();     // obsolescent
void func2(void);

그 행동은 상당히 다르다.첫 번째는 프로토타입 없이 함수를 선언합니다.인수가 몇 개 필요해도 상관없습니다.후자는 프로토타입을 사용하여 함수를 선언하는 반면, 이 함수는 매개 변수를 포함하지 않으며 인수를 수락하지 않습니다.

정의상

void func1() { }     // obsolescent

그리고.

void func2(void) { }
  • 합니다.func1매개 변수와 프로토타입이 없는

  • 합니다.func2 파라미터가 없는 프로토타입을 가지고 있습니다.

C 컴파일러는 잘못된 수의 인수로 프로토타입 함수를 호출할 때 진단 메시지를 출력해야 하지만 프로토타입 없이 함수를 호출할 때는 출력할 필요가 없습니다.

즉, 위의 정의에 따라

func1(1, 2, 3); // need not produce a diagnostic message
func2(1, 2, 3); // must always produce a diagnostic message 
                // as it is a constraint violation

, 6.5.2p6에 따라 명시적으로 정의되지 않은 동작이기 때문에 두 콜 모두 엄밀하게 일치하는 프로그램에서는 불법입니다.

또한 빈 괄호는 사춘기 기능으로 간주됩니다.

빈 괄호(프로토타입 형식의 파라미터 타입 선언자가 아님)에 함수 선언자를 사용하는 것은 사춘기적인 기능입니다.

그리고.

별도의 파라미터 식별자 및 선언 목록(프로토타입 형식의 파라미터 유형 및 식별자 선언자가 아님)과 함께 함수 정의를 사용하는 것은 오래된 기능입니다.

상세하게

파라미터와 인수라는2개의 관련성이 있지만 다른 개념이 있습니다.

  • 인수란 함수에 전달되는 값입니다.

  • parameters는 함수가 입력되었을 때 인수 값으로 설정된 함수 내의 이름 또는 값입니다.

다음 발췌문:

int foo(int n, char c) {
    ...
}

...

    foo(42, ch);

n ★★★★★★★★★★★★★★★★★」c파라미터입니다. 42 ★★★★★★★★★★★★★★★★★」ch수입니니다다

인용된 발췌문은 함수의 매개 변수에만 관련된 것일 뿐, 시제품이나 함수에 대한 인수에 대해서는 언급하지 않았습니다.


선언문 void func1()가 「」, 「」, 「」를 나타내고 있습니다.func1임의의 수의 인수 사용하여 호출할 수 있습니다.즉, 인수 수에 대한 정보가 지정되어 있지 않습니다(별도의 선언으로서 C99는 이것을 「파라미터 지정이 없는 함수」로서 지정합니다). 반면, 선언은void func2(void)가 「」, 「」, 「」를 나타내고 있습니다.func2인수를 전혀 받지 않습니다.

질문의 인용문은 함수 정의 내에서void func1() ★★★★★★★★★★★★★★★★★」void func2(void)둘 다 함수를 입력할 때 인수 값으로 설정된 변수 이름매개 변수가 없음을 알려줍니다.void func() {}되는 표현입니다.void func();func는 실제로하지 않지만 후자는 입니다.func파라미터 및 그 유형이 지정되지 않은 경우(시제품이 없는 선언).

단, 정의 면에서는 아직 차이가 있습니다.

  • ★★void func1() {}, 단, 시제품은 공표되어 있지 않습니다.void func2(void) {}()리스트가 만, 「」는 「」입니다.(void)는 파라미터 타입 리스트(6.7.5.3.10)입니다.

    void 유형의 이름 없는 파라미터가 목록의 유일한 항목인 특수한 경우 함수에 파라미터가 없음을 지정합니다.

    및 추가 6.9.1.7

    디클리케이터에 파라미터 유형 리스트가 포함되어 있는 경우 리스트에는 모든 파라미터의 유형도 지정됩니다.이러한 디클리케이터는, 같은 변환 유닛내의 같은 함수에의 이후의 콜의 함수 프로토타입으로서도 기능합니다.선언자가 식별자 리스트를 포함할 경우 파라미터의 유형은 다음 선언 리스트로 선언해야 한다.어느 경우든 각 매개변수의 유형은 매개변수 유형 목록에 대해 6.7.5.3에 설명된 대로 조정된다. 결과 유형은 객체 유형이어야 한다.

    에 대한 func1에는 파라미터 유형 리스트가 포함되어 있지 않기 때문에 함수에 프로토타입이 없습니다.

  • void func1() { ... }할 수 , "Calling"은 "입니다.void func2(void) { ... }5.2 인수(6.5.2):

    호출된 함수를 나타내는 식이 프로토타입을 포함하는 유형을 갖는 경우, 인수 수는 매개변수의 수와 일치해야 한다.각 인수는 그 값이 대응하는 파라미터의 타입이 수식되지 않은 오브젝트에 할당될 수 있는 타입을 가져야 한다.

    (내 것을 제외)

    이것은 제약사항입니다.표준에 따르면 준거 구현에서는 이 문제에 대한 진단 메시지를 적어도1개 표시할 필요가 있습니다.하지만 그 이후로는func1에는 시제품이 없습니다.진단 결과를 작성하기 위해 적합한 구현이 필요하지 않습니다.


단, 인수의 수가 파라미터의 수와 동일하지 않은 경우 동작정의되지 않은6.5.2.2p6 입니다.

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

따라서 이론상으로는 C99 컴파일러가 이 경우 오류를 발생시키거나 경고를 진단할 수도 있습니다.StoryTellerclang이 이를 진단할 수 있다는 증거를 제공했지만, GCC가 이를 실행하지 않는 것 같습니다(또한 오래된 불분명한 코드와 호환성을 유지하기 위해서도 필요할 수 있습니다).

void test() { }

void test2(void) { }

int main(void) {
    test(1, 2);
    test2(1, 2);
}

이 「」로 되어 .gcc -std=c99 test.c -Wall -Werror을 사용하다

test.c: In function ‘main’:
test.c:7:5: error: too many arguments to function ‘test2’
     test2(1, 2);
     ^~~~~
test.c:3:6: note: declared here
 void test2(void) { }
      ^~~~~

( 「 」 「 」 「 」 「 」 「 」 「 」 「 」 「 」 。testGCC)에 을 컴파일 시 test2). 준거한 실장은 제약조건 위반이므로 진단해야 합니다.

견적서의 중요한 부분은 아래 굵은 글씨로 강조 표시되어 있습니다.

6.7.5.3 기능 선언자(시제품 포함) 14 식별자 목록은 기능 매개변수의 식별자만 선언한다.함수 정의의 일부인 함수 선언자의 빈 목록은 함수에 매개 변수가 없음을 나타냅니다.함수 정의의 일부가 아닌 함수 선언자의 빈 목록은 매개 변수의 수 또는 유형에 대한 정보를 제공하지 않도록 지정합니다.

따라서 본문이 있는 함수의 파라미터 리스트가 비어 있는 경우에도 파라미터 리스트는 동일합니다.하지만 그것은 함수의 선언일 뿐이다.

void function1(); // No information about arguments
void function2(void); // Function with zero arguments

void function3() {
    // Zero arguments
}

void function4(void) {
    // Zero arguments
}

표준에 따르면 func()와 func(func)는 동일합니까?

안 돼요.func(void)함수는 인수를 전혀 받지 않는다고 합니다.func()함수가 지정되지 않은 수의 인수를 받는다고 합니다. 다 하지만 둘둘 both both both both both both bothfunc()스타일은 더 이상 사용되지 않으므로 사용하면 안 됩니다.

이것은 이전 표준 C의 아티팩트입니다.C99는 이것을 쓸모없다고 표시했다.

6.11.6 기능 선언자:

빈 괄호(프로토타입 형식의 파라미터 타입 선언자가 아님)에 함수 선언자를 사용하는 것은 사춘기적인 기능입니다.

C11 현재, 그것은 여전히 청소년기로 남아 있고 표준에서 제거되지 않았습니다.

함수 정의 내의 빈 매개 변수 리스트는 프로토타입을 포함하지 않거나 매개 변수를 포함하지 않음을 의미합니다.

C11 § 6.9.1/7 함수의 정의 (계속되는 견적의 강조는 나의 것입니다)

함수 정의의 선언자는 정의 중인 함수의 이름과 해당 파라미터의 식별자를 지정합니다.디클리케이터에 파라미터 유형 리스트가 포함되어 있는 경우 리스트에는 모든 파라미터의 유형도 지정됩니다.이러한 디클리케이터는, 같은 변환 유닛내의 같은 함수에의 이후의 콜의 함수 프로토타입으로서도 기능합니다.

질문은 다음과 같습니다.

에 따라func() ★★★★★★★★★★★★★★★★★」func(void)★★★★★★★★★★★★★★★★★★?

ㅇㅇㅇ의 입니다. 두 사람의 본질적인 차이는void func() ★★★★★★★★★★★★★★★★★」void func(void)그들의 전화에 있다.

C11 § 6.5.2.2/2 함수 호출(제약 섹션 내):

호출된 함수를 나타내는 식이 프로토타입을 포함하는 유형을 갖는 경우, 인수 수는 매개변수의 수와 일치해야 한다.각 인수는 그 값이 대응하는 파라미터의 타입이 수식되지 않은 오브젝트에 할당될 수 있는 타입을 가져야 한다.

parameters notice인수에 주의해 주세요.함수는 매개 변수를 포함할 수 없지만 여러 개의 인수를 포함할 수 있습니다.

빈 파라미터로 정의되어 있는 함수는 프로토타입을 도입하지 않기 때문에 호출에 대해 체크되지 않기 때문에 이론적으로는 임의의 수의 인수를 제공할 수 있습니다.

단, 이러한 함수를 적어도1개의 인수로 호출하는 것은 엄밀히 말하면 Undefined Behavior(UB; 정의되지 않은 동작)입니다(Anti Haapala의 코멘트 참조).

C11 § 6 . 5 . 2 . 2 / 6 함수 호출(시멘틱스 섹션 ):

인수 수가 매개 변수 수와 같지 않으면 동작은 정의되지 않습니다.

따라서 차이는 미묘합니다.

  • 가 '하다'로 되어 있는 void인수의 수가 파라미터(타입과 함께)와 일치하지 않는 경우 제약조건 위반(제6.5.2.2/2) 때문에 컴파일되지 않습니다.이러한 상황에서는 컴파일러에 적합한 진단 메시지가 필요합니다.
  • 빈 파라미터로 정의되어 있는 경우 컴파일도 있고 하지 않을 수도 있습니다(컴파일러로부터의 진단 메시지는 필요 없습니다).다만, 이러한 함수를 호출하는 것은 UB입니다.

예:

#include <stdio.h>

void func1(void) { puts("foo"); }
void func2()     { puts("foo"); }

int main(void)
{
    func1(1, 2); // constraint violation, it shouldn't compile
      func2(3, 4); // may or may not compile, UB when called
    return 0;
}

이러한 경우 최적화 컴파일러는 인수를 끊을 수 있습니다.예를 들어 Clang이 위의 코드를 컴파일하는 방법(제외)입니다.func1의 콜에 「」를 붙입니다-01SysV ABI의 x86-64입니다.

main:                                   # @main
        push    rax          ; align stack to the 16-byte boundary
        call    func2        ; call func2 (no arguments given)
        xor     eax, eax     ; set zero as return value
        pop     rcx          ; restore previous stack position (RSP)
        ret

언급URL : https://stackoverflow.com/questions/41803937/func-vs-funcvoid-in-c99

반응형