Scope
C 프로그램에 나타나는 각 identifier 는 해당 소스 코드의 일부 불연속 영역인 scope 내에서만 visible (즉, 사용될 수) 합니다.
한 스코프 내에서, 식별자는 해당 개체들이 서로 다른 name spaces 에 있는 경우에만 둘 이상의 개체를 지정할 수 있습니다.
C에는 네 가지 종류의 스코프가 있습니다:
-
- block scope
- file scope
- function scope
- function prototype scope
목차 |
중첩 범위
동일한 식별자로 명명된 두 개의 서로 다른 개체가 동시에 범위 내에 있고, 이들이 동일한 name space 에 속하며, 범위가 중첩된 경우(다른 형태의 범위 중첩은 허용되지 않음), 내부 범위에 나타나는 선언은 외부 범위에 나타나는 선언을 숨깁니다:
// 여기서의 네임스페이스는 일반 식별자입니다. int a; // 이름 a의 파일 스코프가 여기서 시작됩니다 void f(void) { int a = 1; // 이름 a의 블록 스코프가 여기서 시작됩니다; 파일 스코프 a를 가립니다 { int a = 2; // 내부 a의 스코프가 여기서 시작되며, 외부 a는 가려집니다 printf("%d\n", a); // 내부 a가 스코프 내에 있으며, 2를 출력합니다 } // 내부 a의 블록 스코프가 여기서 끝납니다 printf("%d\n", a); // 외부 a가 스코프 내에 있으며, 1을 출력합니다 } // 외부 a의 스코프가 여기서 끝납니다 void g(int a); // 이름 a는 함수 프로토타입 스코프를 가지며; 파일 스코프 a를 가립니다
블록 범위
복합문(compound statement) 내부에서 선언된 모든 식별자의 범위는, compound statement (함수 본체를 포함), 또는 if , switch , for , while , 또는 do-while 문에 나타나는 모든 표현식, 선언, 문장 (since C99) , 또는 function definition 의 매개변수 목록 내에서 선언된 식별자의 범위는 선언 지점에서 시작하여 해당 식별자가 선언된 블록 또는 문장의 끝에서 종료됩니다.
void f(int n) // 함수 매개변수 'n'의 스코프 시작 { // 함수 본문 시작 ++n; // 'n'은 스코프 내에 있으며 함수 매개변수를 참조함 // int n = 2; // 오류: 동일한 스코프에서 식별자를 재선언할 수 없음 for(int n = 0; n<10; ++n) { // 루프 지역 변수 'n'의 스코프 시작 printf("%d\n", n); // 0 1 2 3 4 5 6 7 8 9 출력 } // 루프 지역 변수 'n'의 스코프 종료 // 함수 매개변수 'n'이 다시 스코프 내로 돌아옴 printf("%d\n", n); // 매개변수의 값을 출력 } // 함수 매개변수 'n'의 스코프 종료 int a = n; // 오류: 이름 'n'이 스코프 내에 없음
|
C99 이전까지는 선택문과 반복문이 자체 블록 범위를 설정하지 않았습니다(해당 문장에서 복합문이 사용된 경우에는 일반적인 블록 범위를 가졌지만): enum {a, b}; int different(void) { if (sizeof(enum {b, a}) != sizeof(int)) return a; // a == 1 return b; // b == 0 in C89, b == 1 in C99 } |
(C99부터) |
블록 범위 변수는 기본적으로 링크 없음(no linkage) 과 자동 저장 기간(automatic storage duration) 을 가집니다. 비 VLA 지역 변수의 저장 기간은 블록이 시작될 때부터 시작되지만, 선언문이 나타날 때까지는 해당 변수가 스코프에 들어오지 않으며 접근할 수 없습니다.
파일 범위
블록이나 매개변수 목록 외부에서 선언된 모든 식별자의 범위는 선언 지점에서 시작하여 번역 단위의 끝까지 이어집니다.
int i; // i의 스코프 시작 static int g(int a) { return a; } // g의 스코프 시작 ("a"는 블록 스코프를 가짐) int main(void) { i = g(2); // i와 g가 스코프 내에 있음 }
파일 범위 식별자는 기본적으로 external linkage 와 static storage duration 을 가집니다.
함수 범위
함수 내부에 선언된 레이블(그리고 레이블만) 는 해당 함수 전체, 모든 중첩 블록, 그리고 자체 선언 전후에서 스코프를 가집니다. 참고: 레이블은 암시적으로 선언되며, 어떤 문장 앞에 콜론 앞에서 다른 용도로 사용되지 않는 식별자를 사용함으로써 선언됩니다.
void f() { { goto label; // 레이블이 나중에 선언되었더라도 스코프 내에 있음 label:; } goto label; // 레이블은 블록 스코프를 무시함 } void g() { goto label; // 오류: g() 함수 내에서 레이블이 스코프에 없음 }
함수 프로토타입 범위
정의가 아닌 함수 선언 의 매개변수 목록에서 도입된 이름의 범위는 함수 선언자 의 끝에서 종료됩니다.
int f(int n, int a[n]); // n은 스코프 내에 있으며 첫 번째 매개변수를 참조합니다
선언에 여러 개의 선언자나 중첩된 선언자가 있는 경우, 범위는 가장 가까운 바깥쪽 함수 선언자의 끝에서 끝난다는 점에 유의하십시오:
void f ( // 함수 이름 'f'는 파일 스코프에 있음 long double f, // 식별자 'f'가 이제 스코프 안에 있으며, 파일 스코프의 'f'는 가려짐 char (**a)[10 * sizeof f] // 'f'는 스코프 안에 있는 첫 번째 매개변수를 참조함 ); enum{ n = 3 }; int (*(*g)(int n))[n]; // 함수 매개변수 'n'의 스코프는 // 해당 함수 선언자의 끝에서 종료됨 // 배열 선언자에서는 전역 n이 스코프 안에 있음 // (이는 3개의 int를 가진 배열에 대한 포인터를 반환하는 함수에 대한 포인터를 선언함)
선언 지점
구조체, 공용체, 열거형 태그의 범위는 태그를 선언하는 타입 지정자에서 태그가 나타난 직후부터 시작됩니다.
struct Node { struct Node* next; // Node는 범위 내에 있으며 이 구조체를 참조합니다 };
열거형 상수의 범위는 열거자 목록에서 해당 열거형 정의가 나타난 직후부터 시작됩니다.
enum { x = 12 }; { enum { x = x + 1, // 새로운 x는 쉼표까지 범위에 포함되지 않음, x는 13으로 초기화됨 y = x + 1 // 새로운 열거자 x가 이제 범위에 포함됨, y는 14로 초기화됨 }; }
다른 식별자의 범위는 해당 선언자의 끝 바로 다음과 초기화자(있는 경우) 앞에서 시작합니다:
int x = 2; // 첫 번째 'x'의 스코프 시작 { int x[x]; // 새로 선언된 x의 스코프는 선언자(x[x]) 이후부터 시작됩니다. // 선언자 내부에서는 외부 'x'가 여전히 스코프 내에 있습니다. // 이것은 2개의 int를 가진 VLA 배열을 선언합니다. }
unsigned char x = 32; // 외부 'x'의 범위 시작 { unsigned char x = x; // 내부 'x'의 범위는 초기화자(= x) 이전에 시작됨 // 이는 내부 'x'를 값 32로 초기화하지 않으며, // 내부 'x'를 자신의 불확정 값으로 초기화함 } unsigned long factorial(unsigned long n) // 선언자 종료, 이 시점부터 'factorial'이 범위 내에 있음 { return n<2 ? 1 : n*factorial(n-1); // 재귀 호출 }
특별한 경우로, 식별자를 선언하지 않는 type name 의 범위는, 식별자가 생략되지 않았다면 나타났을 type name 내 위치 바로 다음부터 시작되는 것으로 간주됩니다.
참고 사항
C89 이전에는 외부 연결을 가진 식별자가 블록 내에서 도입된 경우에도 파일 범위를 가졌으며, 이로 인해 C89 컴파일러는 범위를 벗어난 extern 식별자 사용을 진단할 필요가 없습니다(이러한 사용은 정의되지 않은 동작입니다).
C 언어에서는 루프 본문 내의 지역 변수가 for 루프의 init 절에 선언된 변수를 가릴 수 있지만(이들의 범위가 중첩됨), C++에서는 이를 할 수 없습니다.
C++와 달리, C에는 구조체 범위가 없습니다: 구조체/공용체/열거형 선언 내에서 선언된 이름들은 구조체 선언과 동일한 범위에 있습니다(단, 데이터 멤버들은 자체적인 멤버 이름 공간 에 있음):
struct foo { struct baz {}; enum color {RED, BLUE}; }; struct baz b; // baz는 스코프 내에 있음 enum color x = RED; // color와 RED는 스코프 내에 있음
참고문헌
- C23 표준 (ISO/IEC 9899:2024):
-
- 6.2.1 식별자, 타입 이름, 복합 리터럴의 범위 (p: TBD)
- C17 표준 (ISO/IEC 9899:2018):
-
- 6.2.1 식별자의 범위 (p: 28-29)
- C11 표준 (ISO/IEC 9899:2011):
-
- 6.2.1 식별자의 범위 (p: 35-36)
- C99 표준 (ISO/IEC 9899:1999):
-
- 6.2.1 식별자의 범위 (p: 29-30)
- C89/C90 표준 (ISO/IEC 9899:1990):
-
- 3.1.2.1 식별자의 범위
참고 항목
|
C++ documentation
for
Scope
|