• 변수와 관련된 용어들
  • 초기화의 중요성 및 대입 연산자와의 차이점
  • 초기화와 관련된 debug 모드와 release 모드의 치명적인 차이점
  • iostream 입출력 스트림의 사용
  • namespace

1.2.1. 변수와 관련된 용어들

 

변수(variables)는 가리키게 되는 메모리 공간의 또 다른 이름이라고 볼 수 있다. 조금은 어려운 정의로 언급하였지만 C++처럼 메모리 공간에 굉장히 가깝게 프로그램을 작성하는 언어에 한정해서는 이렇게 이해하는게 좋다. 코드를 먼저 보고 등장하는 것들에 대해 설명을 이어가도록 하겠다.

 

#include <iostream>

int main()
{
	int x = 123;

	int y;
	y = 123; // assignment operator 대입 연산자
	
	std::cout << y << std::endl;
	std::cout << &y << std::endl; // y의 메모리 주소가 출력된다.

	return 0;
}

변수 x에 대해서는 선언과 동시에 초기화를 해준다. y는 선언과 할당이 이루어지고, 대입 연산자(assignment operator)를 통해 값을 넣어준다.

int y;
y = 123; // assignment operator 대입 연산자
대입 연산자의 정확한 의미는 다음과 같다.
y라는 변수 이름이 가리키고 있는 메모리 공간에 123이라는 정수를 저장해둔다.

 

&(ampersand) 연산자를 통해서 현재 y가 어느 메모리 공간에 저장되어 있는지 주소를 볼 수 있다. x86과 x64에 따라서 주소의 길이는 다르게 표현된다.

 

x = x + 2;

l-value와 r-value에 대한 정의를 간단히 이야기 하면 다음과 같다.
l-value는 메모리 주소를 가지고 있다.(대입 연산자 기준 왼쪽의 x)
r-value는 임시적으로 저장한 뒤 사라진다.(대입 연산자 기준 오른쪽의 x + 2)
x = x + 2;라고 할지라도 오른쪽의 x는 임시적으로 다른 메모리 공간에 x에 담긴 값을 가져온 뒤 2를 더하는 연산이 수행되기 때문에 l-value가 아닌 r-value이다.


1.2.2. 초기화의 중요성 및 대입 연산자와의 차이점

 

추후 생성자 및 소멸자 개념처럼 객체 지향에 대한 개념으로 들어가게 되었을 때, 초기화와 대입을 구분하는 것은 굉장히 중요해진다. 이후 포스팅에서도 언급하겠지만 미리 한번 정리해보도록 하자.

#include <iostream>

int main()
{
	int x; // error C4700: uninitialized local variable 'x' used

	int y = 123; // initialization
	//int y(123); 효율적인 차이는 없다.
    
	int z;
	z = 5; // assignment
    
	std::cout << x << std::endl;

	return 0;
}

y는 초기화를 해준 것이다. z는 쓰레기 값이 들어가 있는 상태로 할당이 된 뒤에 5라는 값이 대입이 되었다. 이처럼 선언과 동시에 의도한 값이 들어가는지에 대한 여부로 초기화와 대입을 구분할 수 있겠다.


1.2.3. 초기화와 관련된 debug 모드와 release 모드의 치명적인 차이점

error 발견

debug 모드에서는 앞에서 소개한 코드를 빌드할 경우 위와 같이 x가 초기화되지 않았다는 경고 메시지가 뜬다. 무시하고서 프로그램을 실행시 runtime error가 뜬다.


release 모드에서는 실행시 자동으로 초기화시켜주는데 기본적인 값을 넣어준다. 여기서 기본적인 값은 어느정도 규칙은 있겠으나 큰 프로그램을 다루는 경우 개발자의 의도와는 다른 값이 들어가서 방해를 할 수도 있다.

 

변수는 항상 초기화를 해주자!!

이전 프로그램이 해당 메모리 주소를 사용하다가 쓰레기 값을 넣어두고 가버리기 때문에 항상 초기화로 바로 잡아야한다.


1.2.4. iostream 입출력 스트림의 사용

 

프로그램을 만들면서 가장 많이 사용하는 것이 바로 입출력 스트림이다. 다음의 코드와 함께 기본적인 용어를 정리해보자!

#include <iostream>
#include <cstdio>

int main()
{
	using namespace std;
    
	int x = 1024;
	double pi = 3.141592;

	std::cout << "I love this lecture!\n"; // << std::endl;
	// <<라는 스트림을 타고 cout으로 들어간다.
	std::cout << "x is " << x << " pi is " << pi << std::endl;
	// pi는 일부가 잘린다. 출력 정밀도 조정이 필요하다!

	std::cout << "abc" << "\t" << "def" << std::endl;
	std::cout << "ab" << "\t" << "cdef" << std::endl;
	// \t는 탭을 의미한다. \t은 빈공간을 주면서 줄맞춤까지 하고 싶을 때 사용하면 좋다.
	// \t는 하나의 기능으로 작동하며 두 글자가 아니다.

	cout << "\a"; // audio의 약자. 소리를 출력해준다.
	//printf("I love this lecture!\n");

	int z = 1;

	cout << "Before your input, z was " << z << endl;

	// z로 input이 흘러들어가는 형태
	cin >> z; //100000000000000000000000과 같은 큰 수를 넣는 경우를 생각하면 입력 유효성 검증이 필요
	
	cout << "Your input is " << z << endl;

	return 0;
}

 

#include <iostream>를 통해 입출력 스트림을 사용할 수가 있다. stream은 흐르는 느낌의 단어인데, 입력과 출력을  사용해보면 마치 그런 느낌이 들도록 구현이 되어 있다. iostream은 input output stream을 축약해서 사용한 것이다.

 

입출력 스트림을 사용하면 기본적으로 아래의 3가지를 많이 다룬다.

 

std::cin은 console in을 줄인 명령어로 무언가를 입력할 때 사용한다.
std::cout은 console out을 줄인 명령어로 무언가를 출력할 때 사용한다.
std::endl은 end line을 의미하는 명령어로 줄바꿈을 수행한다.


1.2.5. namespace

 

C++를 시작하면서 처음 접하게 되는 개념이 namespace였다. namespace는 이름공간, 명칭공간이라고도 하며, 입출력 스트림을 사용할 때마다 앞에 붙여준 std::가 바로 namespace이다. namespace가 다르다면 이름이 같은 함수라도 다른 함수로 인식할 수 있다. cout, cin, endl은 std라는 namespace 안에 정의되어 있다.

 

using namespace std;

이 명령문이 입력된 코드 영역에서는 이제 std::을 생략해도 된다. 컴파일러가 cout이나 endl을 만났을 때, std라는 namespace 안에서 컴파일러가 직접 찾고 컴파일을 해준다.

+ Recent posts