본문 바로가기

지역 변수, 범위, 지속기간 Local variables, scope, duration 본문

💘 C++/변수범위, 변수형

지역 변수, 범위, 지속기간 Local variables, scope, duration

Hyonii 2022. 1. 11. 22:41

블록(block)

블록 (=복합 명령문)

복합 명령문(compound statement)라고도 불리는 블록(block)은 마치 한 명령문 같이 보이는 명령문의 그룹이다.

블록은 { 기호로 시작해서 }기호로 끝나고, 기호 사이에 실행할 명령문을 배치한다.

블록은 단일 명령문이 허용되는 모든 위치에서 사용할 수 있고, 블록 끝에는 세미콜론이 필요하지 않다.

 

블록은 다른 블록 내부에 중첩될 수 있다.

지금까지는 if문에서 조건이 true일 때 단일 명령문을 실행했다.

그러나 블록은 단일 명령문이 허용되는 모든 위치에서 사용할 수 있으므로

중첩된 명령문 블록을 사용하여 조건이 true인 경우 if 문에서 여러 명령문을 실행할 수 있다.

#include <iostream> 
int main() 
{ 
        std::cout << "Enter an integer: "; 
	int value; 
	std::cin >> value; 

	if (value >= 0) 
	{ // start of nested block 
	    std::cout << value << " is a positive integer (or zero)" << std::endl; 
		std::cout << "Double this number is " << value * 2 << std::endl; 
	} // end of nested block 
	else 
	{ // start of another nested block 
	    std::cout << value << " is a negative integer" << std::endl; 
		std::cout << "The positive of this number is " << -value << std::endl; 
	} // end of another nested block
    
	return 0; 
}

블록 내부에 블록을 배치 할 수도 있다.

int main() 
{ 
	std::cout << "Enter an integer: "; 
    int value; 
    std::cin >> value; 
    
    if (value > 0) 
    { 
    	if ((value % 2) == 0) 
        { 
        	std::cout << value << " is positive and even" << std::endl;
        } 
        else 
        { 
        	std::cout << value << " is positive and odd" << std::endl;
        } 
    } 
    
    return 0; 
}

중첩된 블록(nested block) 수에는 제한이 없다.

지역 변수, 스코프 그리고 주기 (Local variables, scope and duration)

변수를 논의할 때 변수의 스코프(=범위)와 주기의 개념을 분리하는 것이 유용하다.

변수의 스코프(scope)에 따라 변수에 접근할 수 있는 위치가 결정된다. 

변수의 주기(duration)는 변수가 생성되고 소멸하는 위치를 결정한다. 

이 두 개념은 밀접하게 관련돼있다.

 

함수 내부에 정의된 변수를 지역 변수(local variable)라고 한다.

지역 변수는 자동 주기(auto duration)를 가지고 있다.

정의되는 시점에서 생성되고 초기화되며, 정의된 블록이 끝나는 지점에서 소멸한다. 

또한, 지역 변수는 지역 스코프(블록 스코프라고도 불린다)를 가진다. 

이는 선언 시점에서 스코프에 들어가고 정의된 블록 끝에서 소크프에서 벗어나는 걸 의미한다.

스코프 내에서만 변수에 접근할 수 있다.

int main() 
{ 
    int i(5); // i created and initialized here 
    double d(4.0); // d created and initialized here 
    
    return 0;
    
} // i and d go out of scope and are destroyed here

변수 i와 d는 main() 함수 내부에서 정의되었기 때문에 main() 함수의 실행이 완료되면 모두 소멸한다.

 

중첩된 블록(nested block) 내부에 정의된 변수는 중첩된 블록이 끝나는 즉시 소멸한다.

int main() // outer block 
{ 
    int n(5); // n created and initialized here 
    
    { // begin nested block 
    	double d(4.0); // d created and initialized here 
    } // d goes out of scope and is destroyed here 
    
    // d can not be used here because it was already destroyed! 
    
    return 0; 
} // n goes out of scope and is destroyed here

블록 내부에 정의된 변수는 해당 블록에서만 접근할 수 있다.

각 함수는 자체 블록을 가지고 있으므로 한 함수의 변수를 다른 함수에서 볼 수 없다.

void someFunction() 
{ 
	int value(4); // value defined here 
    
    // value can be seen and used here 
    
} // value goes out of scope and is destroyed here 

int main() 
{ 
	// value can not be seen or used inside this function. 
    
    someFunction(); 
    
    // value still can not be seen or used inside this function. 
    
    return 0; 
}

다음 예제를 보면 두 함수 각각에 xy 이름의 변수가 있다. 각 함수의 이러한 변수는 다른 함수에 같은 이름을 가진 다른 변수의 존재를 알지 못한다.

#include <iostream> 


// add's x and y can only be seen/used within function add() 
int add(int x, int y) // add's x and y are created here and can only be seen/used within add() after this point 
{ 
    return x + y; 
} // add's x and y are destroyed here 


// main's x and y can only be seen/used within function main() 
int main() 
{ 
    int x = 5; // main's x is created here, and can be seen/used only within main() after this point 
    int y = 6; // main's y is created here, and can be seen/used only within main() after this point 
    
    std::cout << add(x, y) << std::endl; // the value from main's x and y are copied into add's x and y 
    
    // We can still use main's x and y here 
    
    return 0; 
} // main's x and y are destroyed here

중첩된 블록은 외부 블록의 일부로 간주한다.

따라서 외부 블록에서 정의된 변수를 중첩된 블록 내부에서 접근할 수 있다.

#include <iostream> 
int main() 
{ // start outer block 

    int x(5); 
    
    { // start nested block 
        int y(7); 
        // we can see both x and y from here 
        std::cout << x << " + " << y << " = " << x + y; 
    } // y destroyed here 
    
      // y can not be used here because it was already destroyed! 
      
    return 0; 
} // x is destroyed here

숨기기 (hiding/shadowing)

중첩된 블록 내부의 변수는 외부 블록과 같은 이름을 가질 수 있다.

이 경우 외부 블록의 같은 이름의 변수는 잠시 가려지는데 이것을 쉐도잉(shadowing) 또는 숨기기(hide)라고 부른다.

#include <iostream> 
int main() 
{ // outer block 
    int apples(5); // here's the outer block apples 
    
    if (apples >= 5) // refers to outer block apples 
    { // nested block 
        int apples; // hides previous variable named apples 
        
        
        // apples now refers to the nested block apples 
        // the outer block apples is temporarily hidden 
        
        apples = 10; // this assigns value 10 to nested block apples, not outer block apples 
        
        std::cout << apples << '\n'; // print value of nested block apples 
    } // nested block apples destroyed 
    
    // apples now refers to the outer block apples again 
    
    std::cout << apples << '\n'; // prints value of outer block apples 
    
    return 0; 
} // outer block apples destroyed 

//it prints: 
//10 
//5

 

위 프로그램에서 중첩된 블록 내부의 변수 apple은 외부 블록 apple을 숨긴다.

중첩된 블록이 끝나면 중첩된 블록 내부 변수 apple 은 소멸하고 다시 외부 블록 apple에 접근할 수 있게 된다.

만약 중첩된 블록 내부에서 변수 apple을 정의하지 않으면 외부 블록 변수 apple에 접근하여 값 10을 할당한다.

#include <iostream> 
int main() 
{ // outer block 
    int apples(5); // here's the outer block apples 
    
    if (apples >= 5) // refers to outer block apples 
    { // nested block
      // no inner block apples defined
       
      apples = 10; // this now applies to outer block apples, even though we're in an inner block
        
      std::cout << apples << '\n'; // print value of outer block apples 
    } // outer block apples retains its value even after we leave the nested block
    
    
    std::cout << apples << '\n'; // prints value of outer block apples 
    
    return 0; 
} // outer block apples destroyed 

//it prints: 
//10 
//10

중첩된 블록 안에서 외부 블록의 변수와 이름이 같은 변수를 정의하지 말자. 변수는 가능한 한 제한된 스코프(=범위) 안에서 정의되는게 좋다. 예를 들어, 변수가 중첩된 블록 내에서만 사용되는 경우, 해당 중첩된 블록 내에서 정의되도록 하자.

함수 매개 변수 (function parameter)

함수 매개 변수는 함수가 속하는 블록 내에서 정의되지는 않았지만 대부분 블록 스코프를 가진 것으로 간주할 수 있다.

int max(int x, int y) // 변수 x와 y는 함수 매개 변수에서 정의되었다. 
{ 
    // 매개변수는 블록 스코프를 가진것으로 간주되므로 블록 내부에서 접근가능하다. 
    // x와 y중 더 큰 값을 변수 max에 할당한다. 
    int max = (x > y) ? x : y; 
    return max; 
} // 변수 x와 y는 여기서 소멸된다.

namespace

이렇게 있을 경우 이 두개는 충돌난다

 

같은 영역 안에 있는 변수가 이름이 같은 경우 충돌이 난다.

함수 같은 경우에는 달라 보이는 이유가 함수는 선언과 정의를 분리 할 수 있다.

선언은 여기저기 넣어도 괜찮은데 정의는 반드시 한 곳에서만 넣어야 한다.

메모리를 차지 하는 곳은 딱 한 곳 밖에 없다는 개념이다.

 

이렇게 같은 이름의 함수가 두개 있다고 가정 했을 때
이름이 같은데 파라미터가 다른경우

이름이 같은데 파라미터가 다른 경우에는 다른 함수로 간주한다.

충돌도 일어나지 않는다

 

이름도 같고, 파라미터도 같고, return type 도 같은데 하는 일이 다르면

같은 영역 안에 있을 수 없다.

영역을 나누어주어야 한다.

 

영역 두개가 다르다는 것을 확실하게 표현해주기 위해서 이름을 붙여 줄 수 있는데

그것을 namespace 라고 한다.

 

이렇게 work1, work2 이름을 붙여준다

이 떄 :: 이 연산자는 영역 혹은 범위 결정 연산자이다.

scope resolution operator

여기서 resolution 은 충돌이 났을 때 해결해준다는 개념에 가깝다.

 

얘는 work1 안에있는 dosomething 을 의미한다

얘는 work2 안에 있는 dosomething을 의미한다 이렇게 표현해서 해결해준다.

 

C++ 17부터 새로 추가된 기능으로

namespace 안에 namespace를 추가 할 수 있다.

 

이런식으로 계속 추가 가능한데

이런식으로 쓰면 코드가 보기힘드니까

17에서는 얘를

 

빨간 줄 뜬거는 컴파일러 버전을 안바꿔서 그렇다.

이렇게 쓸 수 있다.

 

여기서 17로 바꿔주면 된다.
이렇게 바꿔주면 최신 문법이 적용된다
컴파일러 버전을 17로 바꾸니 문제가 사라짐

 

얘를 접근 할 때에는

이렇게 접근한다.

쓰기 편해지기는 했지만 어쨌든 여러개 들어가면 보기 어려워진다.

중괄호든 namespace 영역이든 depth를 최대한 적게 사용하는 것이 좋다.

Comments