Namespaces
Variants

Function declarations

From cppreference.net

함수 선언은 함수를 지정하는 식별자 를 도입하고, 선택적으로 함수 매개변수의 타입들( 프로토타입 )을 명시합니다. 함수 선언은( 정의 와 달리) 파일 범위뿐만 아니라 블록 범위에서도 나타날 수 있습니다.

목차

구문

함수 선언의 선언 문법 에서, type-specifier 시퀀스(선언자에 의해 수정될 수 있음)는 반환 타입 (배열이나 함수 타입이 아닌 모든 타입일 수 있음)을 지정하며, declarator 는 다음 세 가지 (C23 이전) 두 가지 (C23 이후) 형태 중 하나를 가집니다:

noptr-declarator ( parameter-list ) attr-spec-seq (선택적) (1)
noptr-declarator ( identifier-list ) attr-spec-seq (선택적) (2) (C23 이전)
noptr-declarator ( ) attr-spec-seq (선택적) (3)

여기서

noptr-declarator - 괄호로 묶이지 않은 포인터 선언자를 제외한 모든 declarator . 이 선언자에 포함된 식별자가 함수 지정자(function designator)가 되는 식별자입니다.
parameter-list - 단일 키워드 void 또는 쉼표로 구분된 매개변수 목록이며, 생략 매개변수(ellipsis parameter) 로 끝날 수 있습니다.
identifier-list - 쉼표로 구분된 식별자 목록으로, 이 선언자가 구형 스타일 함수 정의(function definition) 의 일부로 사용될 때만 가능합니다.
attr-spec-seq - (C23) 함수 타입에 적용되는 속성(attributes) 의 선택적 목록
1) 새로운 스타일(C89) 함수 선언. 이 선언은 함수 지정자 자체를 도입함과 동시에 향후 모든 함수 호출 표현식 에 대한 함수 프로토타입 역할을 수행하여, 인수 표현식에서 선언된 매개변수 타입으로의 변환을 강제하고 인수 개수에 대한 컴파일 타임 검사를 수행합니다.
int max(int a, int b); // declaration
int n = max(12.01, 3.14); // OK, conversion from double to int
2) (C23 이전) 구식(K&R) 함수 정의. 이 선언은 프로토타입을 도입하지 않으며, 향후 모든 함수 호출 표현식 에서는 기본 인자 승격을 수행하고, 인자 수가 매개변수 수와 일치하지 않을 경우 정의되지 않은 동작을 유발합니다.
int max(a, b)
    int a, b; // definition expects ints; the second call is undefined
{
    return a > b ? a : b;
}
int n = max(true, (char)'a'); // calls max with two int args (after promotions)
int n = max(12.01f, 3.14); // calls max with two double args (after promotions)
3) 비 프로토타입 함수 선언. 이 선언은 프로토타입을 도입하지 않습니다 (until C23) . parameter-list void 와 동등한 새로운 스타일 함수 선언 (since C23) .

설명

함수의 반환 유형은 specifiers-and-qualifiers 에 있는 타입 지정자에 의해 결정되며, 일반적인 declarations 에서처럼 declarator 에 의해 수정될 수 있습니다. 이는 배열이 아닌 객체 타입이거나 void 타입이어야 합니다. 함수 선언이 정의가 아닌 경우, 반환 타입은 incomplete 일 수 있습니다. 반환 타입은 cvr-qualified가 될 수 없습니다: 모든 qualified 반환 타입은 함수 타입을 구성하기 위해 unqualified 버전으로 조정됩니다.

void f(char *s);                    // 반환 타입은 void
int sum(int a, int b);              // sum의 반환 타입은 int
int (*foo(const void *p))[3];       // 반환 타입은 3개 int 배열에 대한 포인터
double const bar(void);             // double(void) 타입 함수 선언
double (*barp)(void) = bar;         // OK: barp는 double(void)에 대한 포인터
double const (*barpc)(void) = barp; // OK: barpc 또한 double(void)에 대한 포인터

함수 선언자는 자신의 타입 지정자와 한정자를 공유할 수 있는 한 다른 선언자와 결합될 수 있습니다

int f(void), *fip(), (*pfi)(), *ap[3]; // 두 개의 함수와 두 개의 객체를 선언합니다
inline int g(int), n; // 오류: inline 한정자는 함수에만 사용할 수 있습니다
typedef int array_t[3];
array_t a, h(); // 오류: 배열 타입은 함수의 반환 타입이 될 수 없습니다

함수 선언이 어떤 함수 외부에 나타나면, 그것이 도입하는 식별자는 파일 범위 외부 링크 를 가지며, static 이 사용되거나 이전의 정적 선언이 보이는 경우를 제외합니다. 선언이 다른 함수 내부에서 발생하면, 식별자는 블록 범위(그리고 또한 내부 또는 외부 링크)를 가집니다.

int main(void)
{
    int f(int); // 외부 링크, 블록 범위
    f(1); // 정의는 프로그램 내 어딘가에서 사용 가능해야 함
}

함수 정의의 일부가 아닌 선언에서의 매개변수들은 이름을 지정할 필요가 없습니다: function definition (until C23)

int f(int, int); // 선언
// int f(int, int) { return 7; } // 오류: 정의에서는 매개변수 이름을 지정해야 함
// 이 정의는 C23부터 허용됨

매개변수 목록의 각 매개변수는 parameter-list 단일 변수를 도입하는 선언 으로, 다음과 같은 추가 속성을 가집니다:

  • 선언자 내 식별자는 선택 사항입니다 (단, 이 함수 선언이 함수 정의의 일부인 경우는 제외) (until C23)
int f(int, double); // OK
int g(int a, double b); // 역시 OK
// int f(int, double) { return 1; } // 오류: 정의에서는 매개변수 이름을 지정해야 함
// 이 정의는 C23부터 허용됨
  • 매개변수에 허용되는 유일한 저장 클래스 지정자 register 이며, 정의가 아닌 함수 선언에서는 무시됩니다
int f(static int x); // 오류
int f(int [static 10]); // OK (배열 인덱스 static은 저장 클래스 지정자가 아님)
  • 배열 타입의 모든 매개변수는 해당 포인터 타입으로 조정됩니다 , 배열 선언자의 대괄호 사이에 한정자가 있는 경우 한정될 수 있습니다 (since C99)
int f(int[]); // int f(int*)를 선언합니다
int g(const int[10]); // int g(const int*)를 선언합니다
int h(int[const volatile]); // int h(int * const volatile)를 선언합니다
int x(int[*]); // int x(int*)를 선언합니다
  • 함수 타입의 매개변수는 해당 포인터 타입으로 조정됩니다
int f(char g(double)); // int f(char (*g)(double))를 선언합니다
int h(int(void)); // int h(int (*)(void))를 선언합니다
  • 매개변수 목록은 , ... 로 끝나거나 ... (C23부터) 일 수 있습니다. 자세한 내용은 가변 인자 함수 를 참조하십시오.
int f(int, ...);
  • 매개변수는 void 타입을 가질 수 없습니다(하지만 void 포인터 타입은 가질 수 있습니다). void 키워드로만 구성된 특별한 매개변수 목록은 매개변수를 받지 않는 함수를 선언하는 데 사용됩니다.
int f(void); // 정상
int g(void x); // 오류
  • 매개변수 목록에 나타나는 식별자 중 typedef 이름 또는 매개변수 이름으로 처리될 수 있는 것은 typedef 이름으로 처리됩니다: int f ( size_t , uintptr_t ) size_t uintptr_t 타입의 이름 없는 두 매개변수를 취하는 함수에 대한 새로운 스타일 선언자로 파싱되며, " size_t "와 " uintptr_t "라는 이름의 두 매개변수를 취하는 함수 정의를 시작하는 구식 스타일 선언자가 아닙니다.
  • 매개변수는 불완전한 타입을 가질 수 있으며 VLA 표기법을 사용할 수 있습니다 [ * ] (C99부터) (단, 함수 정의 에서는 배열-대-포인터 및 함수-대-포인터 조정 이후의 매개변수 타입이 완전해야 합니다).

속성 지정자 시퀀스 는 함수 매개변수에도 적용할 수 있습니다.

(C23부터)

함수 호출의 세부 메커니즘에 대해서는 function call operator 를 참조하고, 함수에서 반환하는 방법에 대해서는 return 을 참조하십시오.

참고 사항

C++와 달리, 선언자 f ( ) f ( void ) 는 서로 다른 의미를 가집니다: 선언자 f ( void ) 는 매개변수를 받지 않는 함수를 선언하는 새로운 스타일(프로토타입) 선언자입니다. 선언자 f ( ) 지정되지 않은 수의 매개변수를 받는 함수를 선언하는 선언자입니다(함수 정의에서 사용되는 경우 제외).

int f(void); // declaration: takes no parameters
int g(); // declaration: takes unknown parameters
int main(void) {
    f(1); // compile-time error
    g(2); // undefined behavior
}
int f(void) { return 1; } // actual definition
int g(a,b,c,d) int a,b,c,d; { return 2; } // actual definition
(C23 이전)

함수 정의 와 달리, 매개변수 목록은 typedef에서 상속될 수 있습니다

typedef int p(int q, int r); // p는 함수 타입 int(int, int)입니다
p f; // int f(int, int)를 선언합니다

C89에서는, specifiers-and-qualifiers 가 선택 사항이었으며, 생략할 경우 함수의 반환 타입은 기본적으로 int 가 되었습니다( declarator 에 의해 수정될 수 있음).

*f() { // function returning int*
   return NULL;
}
(until C99)

결함 보고서

다음의 동작 변경 결함 보고서들은 이전에 발표된 C 표준에 소급 적용되었습니다.

DR 적용 대상 게시된 동작 올바른 동작
DR 423 C89 반환 타입이 한정될 수 있음 반환 타입은 암묵적으로 한정이 제거됨

참고문헌

  • C23 표준 (ISO/IEC 9899:2024):
  • 6.7.7.4 함수 선언자 (프로토타입 포함) (p: 130-132)
  • C17 표준 (ISO/IEC 9899:2018):
  • 6.7.6.3 함수 선언자 (프로토타입 포함) (p: 96-98)
  • C11 표준 (ISO/IEC 9899:2011):
  • 6.7.6.3 함수 선언자 (프로토타입 포함) (p: 133-136)
  • C99 표준 (ISO/IEC 9899:1999):
  • 6.7.5.3 함수 선언자 (프로토타입 포함) (p: 118-121)
  • C89/C90 표준 (ISO/IEC 9899:1990):
  • 3.5.4.3 함수 선언자 (프로토타입 포함)

참고 항목

C++ documentation for Function declaration