block, namespace, 전역변수

김펭귄·2025년 7월 23일

C++

목록 보기
9/20

compound statement (block)

	int x{ 5 };
    {	
    	// block
        int y{1};		// y 생성 (이 block에서만 사용 가능)
        std::cout << y;	// 1
        
        std::cout << x;	// block에 없으니 바깥 x 사용 (5)
        x++;			// 바깥 x (6)
        
        int x{10};		// 바깥의 x를 대체 (shadowing)
        std::cout << x;	// 10
    }					// x(inner), y 소멸
    
    std::cout << x;		// 6
  • {}으로 block 생성
  • block 안에서의 변수는 block 끝나면 파괴됨. 이는 main과 다른 함수들도 다 동일한 얘기
  • 블럭 안에서의 식별자 인식 순서
    1. 현재 속해있는 block에서의 식별자를 찾아 사용 (shadowing 발생 가능)
    2. 현재 속해있는 block에 식별자가 없다면, 바깥 block으로 이동해 찾아 사용
    3. 한 단계씩 상위로 이동해도 없으면, 최종적으로는 global에서 찾아 사용
  • 이는 block, namespace, global space(전역변수) 등 모든 {}에 동일하게 적용됨

namespace 선언

namespace 네임 스페이스 이름
{
    // content of namespace here
}

간단한 사용법

  • naming collision을 예방할 수 있다
  • namespace::식별자로 namespace 것을 사용
  • ::식별자로 global namespace 것을 사용
namespace Foo // Foo라는 namespace (Foo는 global namespace에 존재)
{
    int doSomething(int x, int y) { return x + y; }
}

namespace Goo // Goo라는 namespace
{
    int doSomething(int x, int y) { return x - y; }
}

// global namespace에 존재
int doSomething(int x, int y) { return x; }
int g_swapchain*;	// global에 존재하는 전역변수

int main()
{
	// Foo, Goo, doSomething 다 global에 있으므로 main에서도 사용 가능
    std::cout << Foo::doSomething(4, 3); // 7
    std::cout << Goo::doSomething(4, 3); // 1
    std::cout << ::doSomething(4, 3); // 4
    std::cout << doSomething(4, 3); // 똑같음 (4)
}
  • scope resolution 없이 식별자를 사용할 경우
    1. 현재 속해있는 namespace에서의 식별자를 찾아 사용
    2. 현재 속해있는 namespace에 식별자가 없다면, 그 상위 namespace로 이동해 찾아 사용
    3. 한 단계씩 상위로 이동해도 없으면, 최종적으로는 global namespace에서 찾아 사용
    4. global에도 없다고 다른 namespace를 찾아 들어가지는 않음 (error)
void eoo() { std::cout << "eoo"; }

namespace Foo 
{
	void foo() { std::cout << "foo"; }

	namespace Goo 
	{
		void goo() { std::cout << "goo"; }

		void print() 
		{
			eoo();	// gloabl
			foo();	// Foo
			goo();	// Goo
     	}
    }
}

int main()
{
	Foo::Goo::print();	// Nested namespace는 이렇게 사용
    
    namespace Active = Foo::Goo;
    Active::print(); 		// Alias 통해 사용도 가능    
}
  • 위의 nested namespace는 아래와 같이도 선언 가능
namespace Foo::Goo	// nested namespace
{
	void print() 
	{
		eoo();
		foo();
		goo();
   	}
}

namespace Foo 	// 나중에 따로 더 추가도 가능
{
	void foo() { std::cout << "foo"; }
}

namespace 공유

  • 같은 이름의 namespace들은 하나의 namespace로 공유된다
  • 다른 cpp, 헤더 파일에서 정의되어 있는 같은 이름의 namespace들도 공유
  • 따라서 기존 namespace에 새로운 Identifier 추가 가능
  • 단, std는 수정 불가능
# add.h
namespace BasicMath
{
    int add(int x, int y) { return x + y; }
}

#pi.h
namespace BasicMath
{
    constexpr double pi{ 3.14 };
}

# main.cpp
#include "add.h"
#include "pi.h"

int main()
{
    std::cout << BasicMath::pi << '\n';
	std::cout << BasicMath::add(3, 4) << '\n';
}

전역변수

  • namespace는 global space에 존재하므로, namespace안에 있는 변수도 일반 전역변수처럼 취급
  • 프로그램 시작 시 메모리에 생성되고 (0으로 초기화), 프로그램 종료시 메모리에서 사라짐
  • const, constexpr의 경우 전역변수 선언 시 초기화를 꼭 해주어야 함
  • ::식별자 로 전역변수 사용 가능
int g_x;				// 0으로 초기화 (자동)
constepxr int g_y {1};	// constexpr은 초기화해줘야 함

namespace foo
{
	int g_x;			// namespace도 global이므로 g_x도 0으로 초기화 (전역변수처럼)
    					// 하지만, 진짜 전역변수인 g_x와는 다른 변수
}

int main() {
	std::cout << g_x;		// 전역변수이므로 0
    std::cout << foo::g_x;	// :: 이용하여 호출 (0)
    
    {
    	std::cout << g_x;	// 전역변수 g_x 호출 (0)
    	int g_x {10};		// 얘는 local 변수
        std::cout << g_x;	// shadowing 발생 (10)
        
        std::cout << ::g_x;	// :: 이용하여 전역변수 호출 가능 (0)
    }	// inner g_x 소멸
}	// 프로그램 종료 시 전역변수g_x, foo::g_x, g_y 소멸

Reference

learn.cpp

profile
반갑습니다

0개의 댓글