본문 바로가기

개발 공부/C++

따라하며 배우는 C++ 4. 변수 범위와 더 다양한 변수형

따라하며 배우는 C++ 

 

4. 변수 범위와 더 다양한 변수형

 

 

 

4.1 지역 변수, 범위Scope, 지속시간 Duration

 

보통 중괄호 안에 선언된 변수는, 그 중괄호가 지나면 변수가 반납되므로 중괄호 밖에선 사용할 수 없다.

 

같은 영역 안에 변수가 이름이 같으면 충돌이 일어난다.

함수의 경우 선언과 정의를 분리할 수 있어서 변수와 이름이 같아도 충돌이 안 난다.

 

namespace를 따로두어 영역을 분리할 수 있다.

 

work1::a;

work1::doSomething();

 

work2::a; //여기서 ::은 scope resolution operator라고 부른다(영역 지정 연산자)

work2::doSomething();

 

 

4.2 전역Global 변수, 정적Static 변수, 내부 연결Internal Linkage, 외부External 연결

 

어떤 블럭 안에서 선언된 지역 변수의 경우, 연결성이 없다고 얘기한다.

한 파일 내부면 모두 쓸 수 있는(ex 전역 변수) 변수일 경우 내부 연결이라고 한다.

한 파일에서 선언한 변수를 다른 파일에서 사용할 경우엔 외부 연결이라고 한다.

 

 

전역 변수와 정적 변수의 차이)

static은 OS로부터 메모리를 받은 종류가 static이라는 뜻이다. (메모리가 정적으로 선언된다)

static은 선언되면 그로부터 선언을 다시 하지 않고 저장되어 있는 주소값의 변수를 그대로 쓴다.

즉, static 변수는 선언 즉시 초기화를 해 주어야 한다.

(보통 반복해서 재사용되는 메모리를 고정해서 사용한다는 뜻)

 

like 싱글톤

 

디버깅할 때 편하지만 일반적인 경우에는 사용 안하는 게 좋다.

메모리 관점에서 생각하는 게 이해가 빠를 것이다.

 

static은 바깥에서 접근하기 힘들다.

= static도 local 변수 중 하나, linkage가 없다.

전역 변수 앞에도 static을 붙이면, 다른 cpp 파일에서 사용할 수 없다. 

 

전역 변수는 다른 곳에서도 사용 가능하다. external linkage

 

다른 cpp 파일에 함수를 정의하고(몸체) 또 다른 파일에 함수의 정의를 써 넣으면

따로 include를 하지 않아도 해당 함수를 사용할 수 있다. 그냥 void doSomething()을 해도 괜찮음.

 

변수 앞에 extern 을 붙이면 모든 cpp에서 사용할 수 있음.

다만 두 번 초기화하면 사용 불가

 

외부 변수를 cpp에서 선언 후 초기화하고 그걸 다시 h 파일에서 선언만 한 후

해당 h 파일을 다른 cpp 파일에 include하면 메모리 낭비를 줄일 수 있다.

 

4.3 using문과 모호성

 

using namespace std;를 하면 후에 std::를 붙일 필요 없음

using std::cout;을 하면 "cout"을 쓸 때만 std::를 붙일 필요가 없음.

 

namespace a에도 my_var가 있고 b에도 my_var도 있을 경우.

 

using namespace는 가급적 전역에서 사용하는 걸 피하는 게 더 좋다.

= 가급적 좁은 영역에 영향을 주는 것이 좋다.

 

 

4.4 auto 키워드와 자료형 추론Type Inference

 

초기화를 하지 않으면 자동으로라도 변수형을 알 수 없으므로 auto 키워드를 쓸 수 없다.

 

위의 경우처럼 함수의 return 값을 기억하지 못할 경우 편하다.

 

함수 return형에도 적용할 수 있다.

하지만 함수의 parameter에는 auto를 사용할 수 없다.

 

함수를 아래와 같이 선언할 수 있다.

(트레일링 선언)

줄 맞춤을 하기도 편하고, 이런 입력형에서 이런 출력형이 나온다는 식으로 직관적으로 보기도 편하다.

 

 

4.5 암시적 형변환 Implicit Type Conversion(coersion) 과 명시적 형변환 Explicit Type Conversion(casting)

 

 

 

암시적 형변환은 컴파일러가 내부적으로 형변환을 하는 경우)

 

 

범위를 넘어가지 않는 한에서 다른 형으로 넘어가는 경우엔 문제가 없다

만약 그렇지 않다면 숫자가 이상해지거나 버려버린다.

 

unsigned끼리 계산한 것은 결과물을 unsigned에 넣으려고 한다. 그래서 음수가 나올 경우 주의해야 한다.

우선순위가 int < unsigned int < long < unsigned long < long long < unsigned long long < float < double < long double

 

 

명시적 형변환)

 

int i = (int) 4.0; //c 스타일 캐스팅

int i = int(4.0); //c++ 스타일 캐스팅

int i = static_cast<int>(4.0); 

 

4.6 문자열 std string 소개

 

string은 사용자 정의 자료형이다.

const string my_hello {"Hello, World"};

와 같은 형태의 초기화도 가능.

 

cin에서 buffer는 space 단위로도 단어를 끊는다.

그래서 space를 포함한 문자열을 입력받고 싶으면

std::getline(std::cin, 문자열 변수);

로 입력 받아야 한다.

 

그러나 이런 경우에도 문제가 발생한다.

 

위의 경우는 magic number가 생기므로 지양하는 것도 좋다.

 

 

 

string안에 사용자 정의 타입으로 프로그래밍 되어서 +를 사용할 수 있는 것이다.

 

a.length()로 a 문자열의 길이를 알 수도 있다.

 

4.7 열거형 enumerated types

 

 

이때 다른 그룹의 enum도 전역 변수처럼 작동하기 때문에, 다른 enum에서라도 요소의 값을 다르게 지정해 주어야 함.

 

이 때 COLOR_RED=-2, COLOR_SKYBLUE = 6, BLUE=7

중간중간 초기화 가능.

이 때 실수로 같은 값을 넣으면 같은 값으로 인식될 수도 있다.

 

내부적으로 정수처럼 작동하지만,

int color_id = COLOR_RED; 는 가능하지만

Color my_color = 3; 처럼 숫자를 바로 넣는 것은 되지 않는다.

(casting은 가능 : Color my_color = static_cast<Color>(3); 처럼)

 

 

cin>>my_color;

처럼 직접 enum형을 입력받을 수 없다.

 

int in_number;

cin>>in_number;

if(in_number==COLOR_BLACK) my_color = COLOR_BLACK;

//이처럼 우회해서 구현할 수는 있다.

 

string str_input;

std::getline(cin, str_input);

if(str_input=="COLOR_BLACK") //이런 경우는 권장하지 않는다.

string으로 입력받으면 오타 날 가능성이 커진다.

 

보통 header 파일에 집어넣고 include해서 쓰는 경우가 많다.

 

 

 

 

4.8 영역 제한 열거형(열거형 클래스) Scoped Enumerations

 

enum은 내부적으로 정수로 변환되어서 비교가 되므로 다른 값이라도 같은 것처럼 인식이 될 수 있다.

이 때 사용하는 것이 enum class

 

 

 

같은 enum끼리는 비교 가능.

 

 

 

4.9 자료형에게 가명 붙여주기 aliases

 

뒤에 언더바 t를 많이 사용함. (type임을 나타내기 위한)

 

 

 

위 자료형과 같은 효과

 

 

코드 유지 보수가 편해짐.

 

 

이렇게 모두 나열하면 힘들 것이다.

 

이렇게 긴 변수형을 짧게 줄여서 가독성을 높일 수도 있음.

 

 

위처럼 using을 이용해 할당하듯 쓸 수도 있다(위와 동일한 기능)

 

4.10 구조체 struct

 

 

 

 

 

대입도 가능

 

 

struct 안에 또 다른 struct를 넣을 수도 있다.

return을 할 수도 있다.

 

struct 안에서 디폴트값 줄 수 있음.

그러나 선언 시 초기화하는 값이 우선시 된다.

 

메모리 크기가 계산한 값만큼 나오지 않을 수 있다.

여러 형의 데이터들을 묶어 struct를 만드므로 여유공간(padding)이 생길 수 있는 것.

이 메모리 용량을 잘 계산해주어야 나중에 최적화가 편하다.