• 변수와 관련된 용어들
  • 초기화의 중요성 및 대입 연산자와의 차이점
  • 초기화와 관련된 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 안에서 컴파일러가 직접 찾고 컴파일을 해준다.

  • 1.1.1 프로그램의 구조
  • 1.1.2 주석 잘 다는 법 
  • 1.1.3 기본적인 서식 맞추기

1.1.1 프로그램의 구조

 

프로그램을 실행시킨다는 것은 운영체제(Operating System, OS)에게 요청을 하는 것이다. 내가 작성한 코드가 컴파일되어 실행 파일이 되고 그 파일을 다루는 것은 OS가 된다. 아래의 코드에 나오는 것들을 간단간단하게 알아보자. 추후에 계속 다룰 용어들이니 용어에 친숙해지는 것을 목표로 가볍게 보면 좋겠다.

 

#include <iostream>

int main(void)
{
	int x = 2;
	x = 5;
	int y = x + 3;

	std::cout << y << std::endl;

	int sight = 10;
    
	// 마법의 물약을 먹어서 시야 거리가 0
	sight = 0;

	return 0;
}

 

#include와 같이 앞에 #이 붙은 것들을 전처리기(preprocessor directive)라고 한다.

 

코드 상에서 빈칸과 빈 줄은 컴파일러가 무시를 한다. 그러니 사람이 보기에 가독성이 좋도록 여백을 배치하는 것이 좋다. 주석 또한 컴파일러가 무시한다.

int는 출력 부분에 해당하며, 여기서는 정수의 약자인 int를 사용하였다.
int main(void), 즉, main 함수는 중요하다. OS는 프로그램을 받았을 때 main 함수를 찾는다. main 함수의 몸체는 중괄호로 묶인다.

세미 콜론(;)으로 완전한 문장, statement가 된다. 기능을 수행하는 줄을 statement라고 하며, statement는 관습적으로 명령문이라고 말한다.

변수, int x = 2;의 경우 정수형의 데이터를 받을 수 있는 메모리 공간을 할당받는 것이다

 

std namespace 이름이 겹칠 수 있는 함수나 변수를 구분하기 위한 공간

return 0; 명령문을 통해 OS에게 출력 값을 반환한다.

 

error C2143: syntax error: missing ';' before '}' 에러가 있다면 항상 구글에 검색해보자.


1.1.2 주석 잘 다는 법

 

요즘은 코드 자체를 문서처럼 다룬다. 그렇기에 코드 자체에서 주석(Comments)을 잘 다는 습관을 지니는 것이 좋다. 주석은 내가 왜 이 프로그램을 만드는지, 무엇을 하고 있는지 기록하는 것이다.

 

// 명령문 위에 주석 달기
명령문의 세미콜론 옆에 주석을 달면 한 페이지를 넘어가는 경우가 많다. 명령문의 위에 적절한 길이로 주석을 달아서 가독성을 높여보자! 또한 명령문을 보고서 직관적으로 알 수 있는 내용은 주석으로 달지 않는다.

/*주석 단축키*/

주석 단축키

visual studio 상단 중앙에 주석을 달 수 있는 버튼이 있다. 주로 단축키를 많이 사용하니 외워두도록 하자!


1.1.3 기본적인 서식 맞추기

 

코드를 작성하는 것에 있어서 모두가 따라야 하는 규칙은 없고 사람이 보기 편하면 된다. 많은 사람이 각자의 규칙이 있겠지만 협업한다면 적절하게 타협하여 같은 규칙을 가져야 협업하기가 좋다.

 

일반적으로 컴파일러는 리터럴이 아닌 빈칸과 빈 줄은 무시하기 때문에 사람이 보기 편하도록 빈칸과 빈줄을 넣어주면 되겠다.

 

#include <iostream>

using namespace std;

// 여러가지 함수 작성 서식
int add(int x, int y) { return x + y; }

int add(int x, int y) { 
return x + y; }

int add(int x, int y) { 
	return x + y; 
}

int add(int x, int y) 
{ 
	return x + y; 
}

int main()
{
	// 이처럼 줄을 바꾸더라도 컴파일러는 무시한다.
	// string 안의 빈칸은 컴파일러가 중요시 여긴다.
	cout << "Hello, World" <<	// 줄바꿈을 행했다면 operator를 뒤에 남겨두는 것이 좋다.
		" Hello Home" << endl;

	// 앞의 빈칸(tab)을 만드는 것을 indenting이라 한다.
	// 프로그래머가 반드시 해줘야하는 부분.

	// 변수 대입 연산자 줄맞춤
	int x			= 1;
	int my_value	= 123;
}

 

위처럼 함수 작성의 서식은 여러가지가 있는데 하나로 통일하는 것이 협업에 좋다. 정답은 없으니 같이 일하는 사람들과 정하자.

 

프로그래머가 반드시 지켜줘야 하는 것 중 하나가 바로 indenting인데, 같은 블럭에 있는 코드 줄은 같은 수준의 들여 쓰기를 써야 한다는 점이다. 이를 안 지키는 것은 프로그래머의 관습을 무시하는 것이므로 반드시 지켜주자! 특히 파이썬에서는 이 indenting으로 코드 블럭을 구분하기 때문에 특히 주의해야 한다.

  • 0.0 C++ 꼭 공부해야 할까?
  • 0.1 프로그래밍 언어란
  • 0.2 C, C++ 언어 소개
  • 0.3 프로그래밍 과정 소개
  • 0.4 통합개발환경의 기본적인 사용법
  • 0.5 비주얼 스튜디오 솔루션, 프로젝트 관리
  • 0.6 코딩하다 막혔을 때는?

0.0 C++ 꼭 공부해야 할까?

 

C++는 굉장히 어렵다. 파이썬, Matlab, C, CUDA, Kotlin 등 많은 언어를 공부하면서 가장 어려웠던 언어가 아닐까 싶다. 하지만 C++가 굉장히 고전 언어인 만큼 배울 수 있는 점이 너무 많고, C++를 정복한다면 많은 프로그래밍 학습에서 높은 효율을 기대할 수 있다.

 

좋은 예술가는 베낀다. 위대한 예술가는 훔친다.

처음부터 잘하는 사람은 드물다. 남이 하는 것을 따라 하고 직접 연습해봐야 한다. 프로그래밍 학습의 기본은 아래와 같다. 실제로 내가 실무에서 하는 방식과 유사한 프로세스이다.

 

0. 올바른 타이핑을 익힌다.
1. 간단한 개념을 이해한다.
2. 예제를 따라 해 본다.
3. 문제가 생기면 해결한다.
4. 예제를 내 마음대로 바꿔본다.

0.1 프로그래밍 언어란

 

프로그래밍 언어에 대해 소개하려 한다. 처음 접하는 이야기라 어려울 수도 있지만, 이해하는 것보다 이런 것들이 있구나~ 정도로 생각하고 넘어가면 더 좋다. 앞으로 많이 접하면서 익숙해질 용어가 되겠다.

 

기계어(Machine Language)

컴퓨터는 전압의 차이로 신호를 인식한다. 0과 1 두 가지만 알아들을 수 있다. 사람은 알아보기 힘든 언어이기 때문에 프로그래밍할 때 사람이 직접 사용하진 않는다. 이처럼 0과 1로만 구성된 사람이 보기 힘든 상태의 언어가 기계어이다.

 

어셈블리 언어(Assembly Language)

CPU가 하는 단위 행위 처리, 메모리 복사 등을 직접적으로 할 수 있는 저수준의 언어이다. 좀 더 사람의 언어와 가까워졌지만 여전히 인간의 언어와는 멀다.

 

고수준 언어(High-Level Languages)

C, C++, Pascal, Java, Javascript 등 사람이 다루기 쉬운 언어일수록 수준이 높은 언어라고 표현한다. 최근에는 사람이 다루기 쉬운 언어가 많이 나오면서 C, C++는 중간 레벨 언어라고 표현하기도 한다.

 

컴파일러(Compiler)

컴파일러(Compiler)는 프로그램이다. C/C++는 컴파일 언어이다. 우리가 사용한 고수준 언어를 컴퓨터가 읽을 수 있는 기계어로 변환해 주는 작업을 해주는 것이 컴파일러이다. 작성한 코드를 실행 파일로 만들어 주며, 이때 만들어지는 실행 파일이 결국 우리가 만들고자 한 프로그램이다. 실행 파일은 하드디스크에 저장이 된다.

 

컴파일 언어의 실행 과정

 

인터프리터(Interpreter)

컴파일 언어와는 다른 언어로 대표적인 것이 인터프리터(Interpreter)이다. 인터프리터는 간단하지만 컴파일 언어보다 더 느리기 때문에 양날의 검이다. 실행 파일을 만드는 경우는 한번 만들고 여러 번 쓸 수 있다. 하지만 인터프리터 언어는 매번 인터프리터를 거쳐야 하므로 느리다. 파이썬 언어가 대표적이다. 인터프리터 또한 프로그램이다.

 

인터프리터 언어의 실행 과정

 

이식성(Portability)

Java가 나타나면서 이식성이라는 특성을 생각해보게 되었다. 같은 언어를 사용하더라도 운영체제에 따라 컴파일러가 다르고 실행 파일이 다르다. 또한 윈도우즈 환경에서는 실행되는 파일이 리눅스 환경에서는 실행되지 않을 수 있다. 이러한 경우를 이식성이 없다고 말한다. 아직까지 윈도우즈와 리눅스 간에 서로 호환이 안되지만 차츰차츰 경계가 허물어지고 있다.

 

이식성이 없는 경우

 

Java로 만들어진 바이트코드는 가상 기계에 맞게 실행시킬 수 있다.

 

이식성이 있는 경우


0.2 C, C++ 언어 소개

 

어셈블리 언어로 개발하기 힘들었던 데니스 리치가 개발한 언어가 C 언어이다. C++는 C에서 객체 지향 개념이 확장되면서 처음 소개되었다. 많은 사람들이 오해하는 것이 있는데, C++는 C 언어에 객체 지향 개념만 얹은 언어가 아니다. 초기에는 그랬을지 몰라도 C 언어와 C++는 오랜 시간 기능이 추가되면서 각자가 유사하면서도 다른 길을 가게 되었다. 

 

C/C++ 언어의 설계 철학 - 프로그래머를 믿어라
실제 세계에서 쓸모가 있어야 한다.
프로그래머가 스스로 스타일을 선택할 수 있어야 한다.
유용한 기능을 추가하는 것이 오용보다 더 중요하다.
프로그래머의 의도를 알 수 없다면 스스로 명시하게 한다.
C++ 아래에 다른 언어는 없다.(파이썬 내부는 C++로 구성되어 있다.)

0.3 프로그래밍 과정 소개

 

간단하게 프로그래밍 과정을 살펴보자. 마찬가지로 완벽히 알 필요 없이 이러한 흐름으로 흘러가는구나~ 정도로만 이해해도 된다.

 

풀어야 할 문제를 정의한다.
해법을 설계한다.
해법을 구현하는 프로그램을 작성한다.
프로그램을 컴파일한다.
오브젝트 파일들을 링킹한다.
테스트를 해보고 문제가 있으면 고친다.(디버깅)

 

실행 파일이 만들어지는 과정(g++ -c file1.cpp file2.cpp file3.cpp)

 

런타임 서포트(Runtime Support)는 다른 곳에서 지원해주는 파일로 기억하면 되겠다. 각각의 소스 파일은 컴파일을 통해 오브젝트 파일로 변하고 링킹을 통해 실행 파일을 생성하게 된다.


0.4 통합개발환경의 기본적인 사용법

 

언어는 영어로 하는게 좋다. 오류 검색이나 정보 검색에 있어서 영어가 더 많기 때문이다.

 

visual studio에서 도구 -> 도구 및 기능 가져오기 -> 언어 팩으로 진입한 뒤 영어를 다운

그 뒤에 visual studio 상단 검색창에 언어를 검색하면 변경할 수 있는 항목이 나온다.

 

Hello, World

가장 기본적인 헬로 월드를 작성한 프로그램이다. 하나하나 살펴보도록 하자! 

 

헤더 파일을 포함

include를 사용하면 파일을 가져와서 현재 내 프로그램에 포함시킨다. 여기서는 입출력 헤더를 포함하였다. 부등호를 angle bracket이나 carot으로 부르기도 한다.

 

Build 탭의 구성

빌드는 앞에서 언급한 컴파일과 링킹을 하는 것이다. 실무에서도 빌드를 자주하는데, 단축키를 외워두는 것이 편하다. 자 그럼 컴파일과 링킹을 했으니, 오브젝트 파일과 실행 파일을 찾아보자.

 

내 코드를 오른 클릭

Open Containing Folder를 누르면 해당 소스 코드가 존재하는 파일이 열린다.

 

폴더의 구성 요소

vcxproj는 프로젝트 정보를 담고 있다. Source.cpp는 작성한 코드 자체 파일이다. Debug나 Release 파일이 만들어져 있을텐데 내부에 들어가면 오브젝트(obj) 파일이 만들어져 있을 것이다.

 

실행 파일

응용 프로그램이 실행 파일이 되겠다. 오브젝트 파일과는 다른 폴더에 있을텐데 오브젝트 폴더에서 상위로 두번 이동한 뒤에 Debug 폴더에 진입하면 있을 것이다.

 

Debug 탭의 구성

Start without Debugging을 통해 응용 프로그램을 visual studio 내에서 실행할 수 있다. visual studio가 아닌 곳에서 실행할 수 있는 방법 또한 존재한다.

 

설치한 버전에 따라서 뒤의 년도가 다를 것이다. 실행하면 명령 프롬프트 창이 뜰 것이고 열고자 하는 응용프로그램이 존재하는 디렉토리 위치로 이동할 수 있도록 cd 명령어를 통해 해당 위치로 진입한 뒤 응용프로그램의 이름을 타이핑해보자. 굳이 전부를 타이핑하지 않더라도 일부 타이핑 뒤에 cmd 창에서 탭누르면 유사 파일 이름이 바로 타이핑된다.

 

이동한 뒤에 실행

 

Debug & Release

디버그 모드와 릴리즈 모드이다. 차이점은 실행 파일의 크기가 굉장히 많이 차이난다. 디버그 모드의 실행 파일은 디버깅할 때 도움이 될만한 내용이 모두 담겨 있고 릴리즈 모드의 실행 파일은 배포를 위한 파일이기 때문에 최소한의 내용만 담고 있다. 결국 실행 속도의 차이가 발생한다.

 

x84 & x64

x86은 32비트 환경을 의미한다. x64는 64비트 환경이다. 예전에는 32비트 환경으로 만들어진 프로그램이 많았지만 요즘은 64비트 환경이 더 많으므로 기본으로 x64를 선택하자. 하지만 64비트 환경에서는 개발한 프로그램이 커질 수 있다.

 

visual studio 이외에 Code::Blocks라는 통합개발환경이 존재하는데, 리눅스와 윈도우즈 환경을 자주 오가는 개발자들이 사용하기에 적합하다. 이런게 있다는 정도만 알고 넘어가자!


0.5 비주얼 스튜디오 솔루션, 프로젝트 관리

 

비주얼 스튜디오를 실행하면 최초에 솔루션을 하나 만들고 프로젝트 또한 만들어진다. 솔루션은 하나만 존재해야하지만 프로젝트는 하나의 솔루션에 여러개가 존재해도 된다. 각 프로젝트 파일엔 main 함수가 존재하게 되는데, 빌드를 할 경우에 내가 위치한 프로젝트가 빌드된다.

Project1이 빌드된다.

현재는 Project1이 볼드체로 되어 있기 때문에 빌드를 할 경우 Project1이 빌드된다. Project2로 넘어가고 싶다면 오른 클릭 후 Set as StartUp Project를 클릭하면 Project2로 넘어간다. 그 뒤 빌드하면 Project2에 대한 실행 파일이 생긴다. 프로젝트를 지우고 싶다면 Remove를 사용하여 연결을 끊고 파일 자체를 지우자!

솔루션과 프로젝트


0.6 코딩하다 막혔을 때는?

 

당황하지도, 분노하지도 말자
1. IDE의 도움을 받는다.
2. 검색엔진의 도움을 받는다.(가급적 google -> stackoverflow)
3. 커뮤니티의 도움을 받는다.

+ Recent posts