Declarations
선언 은 하나 이상의 식별자 를 프로그램에 도입하고 그 의미와 속성을 지정하는 C 언어 구성체입니다.
선언은 어떤 영역에서든 나타날 수 있습니다. 각 선언은 세미콜론으로 끝나며 ( 문(statement) 와 마찬가지로) 두 (C23까지) 세 (C23부터) 가지 구별되는 부분으로 구성됩니다:
specifiers-and-qualifiers
declarators-and-initializers
(선택적)
;
|
(1) | ||||||||
attr-spec-seq
specifiers-and-qualifiers
declarators-and-initializers
;
|
(2) | (C23부터) | |||||||
attr-spec-seq
;
|
(3) | (C23부터) | |||||||
여기서
| specifiers-and-qualifiers | - |
공백으로 구분된 목록, 순서 무관
|
| declarators-and-initializers | - | 쉼표로 구분된 선언자 목록 (각 선언자는 추가 타입 정보 및/또는 선언할 식별자를 제공함). 선언자는 초기화자 와 함께 사용될 수 있음. enum , struct , 및 union 선언은 선언자 를 생략할 수 있으며, 이 경우 열거 상수 및/또는 태그만 도입함. |
| attr-spec-seq | - | (C23) 선택적 속성 목록, 선언된 개체에 적용되거나 단독으로 나타날 경우 속성 선언을 형성함. |
예를 들어,
int a, *b=NULL; // "int"는 타입 지정자입니다, // "a"는 선언자입니다 // "*b"는 선언자이고 NULL은 초기화자입니다 const int *f(void); // "int"는 타입 지정자입니다 // "const"는 타입 한정자입니다 // "*f(void)"는 선언자입니다 enum COLOR {RED, GREEN, BLUE} c; // "enum COLOR {RED, GREEN, BLUE}"는 타입 지정자입니다 // "c"는 선언자입니다
선언에서 도입된 각 식별자의 유형은 타입 지정자(type specifier) 에 의해 지정된 타입과 선언자(declarator) 에 의해 적용된 타입 수정의 조합으로 결정됩니다. 변수의 타입은 auto 지정자가 사용된 경우 추론될 수도 있습니다. (C23부터)
속성(Attributes) (C23부터) 는 specifiers-and-qualifiers 에 나타날 수 있으며, 이 경우 앞에 나온 지정자들에 의해 결정된 타입에 적용됩니다.
목차 |
선언자
각 선언자는 다음 중 하나입니다:
| identifier attr-spec-seq (optional) | (1) | ||||||||
(
declarator
)
|
(2) | ||||||||
*
attr-spec-seq
(optional)
qualifiers
(optional)
declarator
|
(3) | ||||||||
noptr-declarator
[
static
(optional)
qualifiers
(optional)
expression
]
noptr-declarator
|
(4) | ||||||||
noptr-declarator
(
parameters-or-identifiers
)
|
(5) | ||||||||
D
를
S
로 결정된 타입의
N
개 객체를 가지는 배열로 선언합니다.
noptr-declarator
는 괄호로 묶이지 않은 포인터 선언자를 제외한 다른 모든 선언자입니다.
D
를 매개변수
params
를 취하고
S
를 반환하는 함수로 선언합니다.
noptr-declarator
는 괄호로 묶이지 않은 포인터 선언자를 제외한 다른 모든 선언자입니다.
이 구문의 배경에는 선언자에 의해 선언된 식별자가 선언자와 동일한 형태의 표현식에 나타날 때, 해당 식별자가 타입 지정자 시퀀스에 의해 지정된 타입을 가지게 된다는 점이 있습니다.
struct C { int member; // "int"는 타입 지정자입니다 // "member"는 선언자입니다 } obj, *pObj = &obj; // "struct C { int member; }"는 타입 지정자입니다 // 선언자 "obj"는 struct C 타입의 객체를 정의합니다 // 선언자 "*pObj"는 C를 가리키는 포인터를 선언합니다 // 초기화자 "= &obj"는 해당 포인터의 초기값을 제공합니다 int a = 1, *p = NULL, f(void), (*pf)(double); // 타입 지정자는 "int"입니다 // 선언자 "a"는 int 타입의 객체를 정의합니다 // 초기화자 "=1"은 초기값을 제공합니다 // 선언자 "*p"는 int를 가리키는 포인터 타입의 객체를 정의합니다 // 초기화자 "=NULL"은 초기값을 제공합니다 // 선언자 "f(void)"는 void를 취하고 int를 반환하는 함수를 선언합니다 // 선언자 "(*pf)(double)"는 double을 취하고 int를 반환하는 함수에 대한 // 포인터 타입의 객체를 정의합니다 int (*(*foo)(double))[3] = NULL; // 타입 지정자는 int입니다 // 1. 선언자 "(*(*foo)(double))[3]"는 배열 선언자입니다: // 선언된 타입은 "/중첩 선언자/ 3개의 int 배열"입니다 // 2. 중첩 선언자는 "*(*foo)(double))"이며, 이는 포인터 선언자입니다 // 선언된 타입은 "/중첩 선언자/ 3개의 int 배열에 대한 포인터"입니다 // 3. 중첩 선언자는 "(*foo)(double)"이며, 이는 함수 선언자입니다 // 선언된 타입은 "/중첩 선언자/ double을 취하고 3개의 int 배열에 대한 // 포인터를 반환하는 함수"입니다 // 4. 중첩 선언자는 "(*foo)"이며, 이는 (함수 선언자 구문에 의해 요구되는 // 대로 괄호로 묶인) 포인터 선언자입니다 // 선언된 타입은 "/중첩 선언자/ double을 취하고 3개의 int 배열에 대한 // 포인터를 반환하는 함수에 대한 포인터"입니다 // 5. 중첩 선언자는 "foo"이며, 이는 식별자입니다 // 이 선언은 식별자 "foo"를 "double을 취하고 3개의 int 배열에 대한 포인터를 // 반환하는 함수에 대한 포인터" 타입의 객체를 참조하도록 도입합니다 // 초기화자 "= NULL"은 이 포인터의 초기값을 제공합니다 // 만약 "foo"가 선언자 형태의 표현식에서 사용된다면, 그 타입은 int가 될 것입니다 int x = (*(*foo)(1.2))[0];
다른 선언자의 일부가 아닌 모든 선언자의 끝은 시퀀스 포인트 입니다.
모든 경우에, attr-spec-seq 는 선택적인 속성 시퀀스입니다 (C23부터) . 식별자 바로 뒤에 나타날 때, 이는 선언되는 객체나 함수에 적용됩니다.
정의
정의 는 선언하는 식별자에 관한 모든 정보를 제공하는 선언입니다.
함수의 경우, 함수 본문을 포함하는 선언은 함수 정의 입니다:
int foo(double); // 선언 int foo(double x) { return x; } // 정의
객체의 경우, 저장 공간을 할당하는 선언( 자동 또는 정적 , 단 extern은 제외)은 정의이지만, 저장 공간을 할당하지 않는 선언( 외부 선언 )은 정의가 아닙니다.
extern int n; // 선언 int n = 10; // 정의
structs 와 unions 의 경우, 멤버 목록을 지정하는 선언은 정의입니다:
struct X; // 선언 struct X { int n; }; // 정의
재선언
같은 식별자에 대한 다른 선언이 동일한 scope 에서 더 일찍 나타나면 선언은 해당 식별자를 도입할 수 없습니다. 단, 다음 경우는 예외입니다.
- 링크를 가진 객체 선언 (외부 또는 내부) 은 반복될 수 있습니다:
extern int x; int x = 10; // 정상 extern int x; // 정상 static int n; static int n = 10; // 정상 static int n; // 정상
- Non-VLA typedef 는 동일한 타입을 지정하는 한 반복될 수 있습니다:
typedef int int_t; typedef int int_t; // 정상
struct X; struct X { int n; }; struct X;
이러한 규칙들은 헤더 파일 사용을 단순화합니다.
참고 사항
|
C89에서는 모든 복합 문 (블록 범위) 내의 선언들은 블록의 시작 부분, 모든 문 이전에 나타나야 합니다. 또한 C89에서는 int 를 반환하는 함수들은 함수 호출 연산자 에 의해 암시적으로 선언될 수 있으며, 올드 스타일 함수 정의 를 사용할 때 int 타입의 함수 매개변수들은 선언되지 않아도 됩니다. |
(C99까지) |
빈 선언자는 허용되지 않습니다; 단순 선언은 적어도 하나의 선언자를 포함하거나, 적어도 하나의 구조체/공용체/열거형 태그를 선언하거나, 적어도 하나의 열거형 상수를 도입해야 합니다.
|
선언자의 어떤 부분이 가변 길이 배열 (VLA) 선언자인 경우, 전체 선언자의 타입을 "가변 수정 타입"이라고 합니다. 가변 수정 타입으로부터 정의된 타입들도 가변 수정(VM)됩니다. 가변 수정 타입의 선언은 블록 범위 또는 함수 프로토타입 범위에서만 나타날 수 있으며, 구조체나 공용체의 멤버가 될 수 없습니다. VLA는 자동 또는 할당된 저장 기간 만 가질 수 있지만, VLA에 대한 포인터와 같은 VM 타입은 정적일 수 있습니다. VM 타입 사용에 대한 다른 제한 사항들이 있으며, goto , switch , longjmp 를 참조하십시오. |
(C99부터) |
|
static_asserts 는 C 문법의 관점에서 선언으로 간주되므로(선언이 나타날 수 있는 어느 곳이든 나타날 수 있음), 하지만 어떤 식별자도 도입하지 않으며 선언 구문을 따르지 않습니다. |
(C11부터) |
|
속성
선언은 또한 선언으로 간주되므로(선언이 나타날 수 있는 어디든 나타날 수 있음), 그러나 식별자를 도입하지는 않습니다.
|
(C23부터) |
참조문헌
- C23 표준 (ISO/IEC 9899:2024):
-
- 6.7 선언 (p: TBD)
- C17 표준 (ISO/IEC 9899:2018):
-
- 6.7 선언 (p: 78-105)
- C11 표준 (ISO/IEC 9899:2011):
-
- 6.7 선언 (p: 108-145)
- C99 표준 (ISO/IEC 9899:1999):
-
- 6.7 선언 (p: 97-130)
- C89/C90 표준 (ISO/IEC 9899:1990):
-
- 3.5 선언
참고 항목
|
C++ 문서
참조:
선언
|