2024. 8. 20. 21:34ㆍ코딩과 프로그래밍/C++
지난 글에서 언급했듯이 이번 글에선 C++에 대해 좀 더 자세히 다뤄보려고 한다. 일단 위와 같이 코드가 써진 것들을 하나하나 해석해보도록 하겠다.
일단 글 앞에 //가 입력된 것은 '주석'을 의미한다. 이는 C언어와 C++ 모두 공통적으로 사용하는데. 우리는 VS에선 주석 글들을 기본적으로 초록색으로 표시해준다. 우린 이러한 글들을 모두 지울 것이다.
주석 글들을 모두 지웠다면 위와 같이 깔끔하게 바뀌었을텐데, 일단 왼쪽에 표시된 '숫자'를 기반으로 설명을 하도록 하겠다.
1번 #include <iostream>이란 입력과 출력을 위한 헤더 파일을 불러온 것이다. 표준 입출력 스트림 라이브러리를 포함하는 명령어이니 거의 항상 쓰는 편이라고 생각하면 된다.
2번은 비어있는 줄로 아무 코드가 작성되어 있지 않았다는 걸 의미하는데. 이 비어있는 줄이 세 줄이든, 네 줄이든 문제는 없으니 참고하도록 하자.
3번의 int main() 부분은 프로그램의 시작점을 나타내는 함수이다. 이를 진입점(entry point)라고도 한다. 시작점은 대부분의 프로그래밍 언어에선 단 한 개만이 작성된다. 시작점이 여러 개인 프로그래밍 언어는 없다고 보면 된다.
4번과 6번의 { } 부분은 중괄호 라고 하며 코드 블록을 정의하거나 초기화 리스트로 사용한다. 코드는 항상 저 중괄호 안에 작성되며 int main()이라는 함수가 실행이 되면 해당 중괄호 안에 있는 코드들이 실행이 된다.
5번의 std::cout << "Hello world!\n"; 라는 코드는 C++에서 콘솔 화면(명령프롬프트, CMD)에 Hello World라는 문자열이나 데이터를 출력하는 명령어이다. 특히 cout는 C++ 표준 라이브러리의 일부로 iostream 헤더 파일에 정의되어 있다. 그래서 cout를 사용하기 위해선 코드의 시작 부분에 #include <iostream>을 포함해야한다. 또 cout는 character output의 약자이다. 하나하나 분석해보도록 하자.
std::cout에서 std는 C++ 표준 라이브러리의 네임스페이스이다. 네임스페이스는 이름 충돌을 방지하기 위해 사용되며 C++ 표준 라이브러리에서 제공하는 모든 기능은 std:: 네임스페이스 안에 포함되어 있다. 여기서 std는 standard의 약자이다.
그리고 using namespace에 대해서도 알아야 하는데, using namespace란 C++에서 특정 네임스페이스를 코드 내에서 명시적으로 지정하지 않고 그 안의 요소들을 직접적으로 사용 할 수 있도록 하게끔 만들어주는데, using namespace std; 라고 하면 std::cout를 단순히 cout로 작성해서 사용 할 수 있다. 아래의 예시 코드를 보자.
#include <iostream>
using namespace std; // std 네임스페이스를 사용하겠다고 선언
int main() {
cout << "Hello, World!" << endl; // std::cout을 그냥 cout으로 사용
return 0;
}
좀 더 자세히 설명하면 표준 C++ 라이브러리의 모든 기능은 std라는 네임스페이스 안에 정의되어 있다, 그래서 cout 라든가, cin나 endl 같은 표준 라이브러리 기능을 사용하기 위해선 std::cout, std::cin과 같이 std::를 앞에 붙여서 사용해야 한다. 근데, using namespace는 특정 네임스페이스에 있는 이름들을 사용할 때 네임스페이스를 명시하지 않도록 해준다.
아래 추가 예시를 통해 좀 더 이에 대해 자세하게 설명하도록 하겠다.
#include <iostream>
int main()
{
std::cout << "Hello, World!" << std::endl;
return 0;
}
분명 필자는 std는 네임스페이스라고 앞서 설명했다. 그래서 cout를 사용하기 위해선 위 코드처럼 std::를 계속 명시해야하는데. 코드 안에 using namespace std;를 추가하면 std::를 사용하지 않아도 된다. 아래의 예시를 보며 위에 있는 코드와 아래에 있는 코드, 두 코드를 비교해보도록 하자.
#include <iostream>
using namespace std;
int main()
{
cout << "Hello, World!" << endl;
return 0;
}
앞서 먼저 작성한 위 코드에선 cout와 endl 앞에 std::를 꼭 항상 명시해줬지만, 아래의 코드와 같이 using namespace std;를 작성한 코드 같은 경우 cout와 endl 앞에 std::를 작성하지 않았다. 그럼에도 불구하고 정상적으로 코드는 작동한다.
자, 그렇다면 우리가 만약 cout를 이용해 출력할 일이 많은 경우 using namespace std;를 활용하면 굳이 매번 cout와 endl를 작성할 때마다 std::를 작성 할 필요가 없다는 것이다. 즉, 코드를 간결하게 만들어준다는 것이다. 다만, 간결화가 되었다는 것은 반대로 명확성이 줄어들었다는 얘기이기도 하니 참고하도록 하자.
또, using namespace std; 외에도 using std:: 같은 코드 또한 있는데. 아래의 코드를 통해 설명하도록 하겠다.
#include <iostream>
using std::cout; // cout는 지금부터 std::로 명시하지 않아도 됨.
int main() {
cout << "Hello, World!" << std::endl; // endl은 여전히 std::로 명시해야함.
return 0;
}
여기서 이미 눈치챈 사람들은 있겠지만, using std::는 특정 이름만 사용하기 때문에 안전성과 명확성이 높아진다는 장점이 있다. using namespace std;는 std 네임스페이스에 포함된 모든 이름(함수, 변수, 클래스 등)을 std::를 명시하지 않고 사용하기 때문에 편리하긴 하지만, 다른 이름들과 충돌 할 수 있는 위험성이 커진다.
만약에 안정성 있게 코드를 작성하고 싶다면 using std::를 사용하는 걸 추천한다. 다만, 일일이 아래와 같이 코드를 작성해주어야 한다.
using std::cout;
using std::endl
약간 using namespace std;에 비해 번거롭긴 하지만, 이 코드 또한 안전성과 편리함을 모두 가져갈 수 있다.
자, 지금까지 5번째 코드에서 std::와 cout에 대해 설명했으며 <<부터 다시 이어나가 설명하도록 하겠다. << 는 연산자로 출력 연산자라고 한다. std::cout와 Hello C++ world 문자열을 연결하여 출력하는 것을 도와주는 역할이다. 여기서 추가로 설명하자면 << 연산자는 비트 시프트 연산자와 입출력 연산자로 사용되는데. 위 코드에선 입출력 연산자로 사용된것이다.
<< 연산자는 비트 시프트 연산자로 이진수의 각 비트를 왼쪽으로 이동시키는 연산인데.x << y 라고 작성되어 있을 경우 x의 비트를 y만큼 왼쪽으로 이동시킨다. 또 오른쪽에서 채워지는 비트는 0이 된다. 아래의 코드를 보고 이해해보도록 하자.
int x = 5; //여기서 5는 이진수, 이진수로 0000 0101 이라는 비트를 가지고 있음.
int y = x << 1; //y의 값은 10이 됨, 이진수로 0000 1010 이라는 비트를 가지고 있음.
위 코드에선 x << 1은 'x'의 비트를 왼쪽으로 1칸 이동시켜 10이 된다는 것이다.
좀 더 자세하게 설명해보도록 하겠다. 일단 int x = 5; 라는 코드는 정수형 데이터인 x라는 변수를 선언하고 그 x라는 변수에 5라는 값을 초기화(할당)한 것을 의미한다. 다음은 근데 5를 이진수로 나타내면 0000 0101인데. 0000 0101을 다음과 같이 계산하면
0x2⁷ = 0
0x2⁶ = 0
0x2⁵ = 0
0x2⁴ = 0
0x1³ = 0
1x2² = 4
0x2¹ = 0
1x2⁰ = 1
4 + 1 = 5
라는 결과가 나온다.
여기서 비트 시프트 연산을 할 경우 x << 1 연산은 x의 모든 비트를 왼쪽으로 1만큼 이동시키게 된다. 또이때앞서 말했듯이 오른쪽에 생기는 빈 자리는 0으로 채워진다. 그리고 왼쪽 끝에서 밀려난 비트는 버려진다.
0000 0101 이라는 비트가 왼쪽으로 1만큼 이동된다고 해보자. 그럼 어떻게 되는가?
0000 1010이 된다.
0x2⁷ = 0
0x2⁶ = 0
0x2⁵ = 0
0x2⁴ = 0
1x2³ = 8
0x2² = 0
1x2¹ = 2
0x2⁰ = 0
따라서 8 + 2 = 10이 된다. 좀 더 쉽게 설명하면 5라는 숫자의 이진수 표현인 0000 0101을 왼쪽으로 1비트 시프트(shift, 옮기다)하여 10이라는 값을 얻는 것이다. 이진수에서의 비트 시프트 연산은 숫자를 2의 제곱 배수만큼 곱하는 효과를 가지므로 x << 1은 x의 값을 2배로 만드는 것과 같다.
그래서 아래와 코드를 작성시 x의 값이 10이 되는 것이다.
int x = 5;
int y = x << 1;
즉, 5 << 1은 '10'
만약 이 같은 개념을 이해 못한다면 이진수와 2진법, 이산수학에 대해서 공부하려고 하자. C언어 때도 얘기했지만, 간단하게 프로그래밍 언어를 배우고 간단한 프로그램을 만들 때는 수학에 대한 지식이 크게 필요 없어도 결국 수학에 대한 지식과 수학적 사고력은 프로그래밍 할 때 큰 도움이 된다. 참고로 필자는 수포자에 고졸인데, 여러분들이라고 못 할까? 무언가를 배울 때 자신감을 갖고 하면 좋겠다.
이어서 "hello c++ world"는 출력할 문자열이다. 문자열이란 건 문자들의 연속된 시퀀스로 C++에선 문자열을 더 쉽게 다룰 수 있도록 표준 라이브러리에서 제공하는 std::string 클래스를 사용하는 것이 일반적이다. std::string은 메모리 관리를 자동으로 처리해주어 다양하고 편리한 메서드를 제공하는데. 멤버 함수들을 통해 아래와 같은 기능들을 제공한다.
문자열의 길이, str.legth() 또는 str.size()는 문자열의 길이를 반환한다. 한 번 아래의 코드를 직접 작성해본뒤 실행은 하지말고 문자열의 길이를 추측해보자. 추측하는 방법은 간단하다. std::string str = "Hello, World", 코드에서 " "안에 있는 모든 것들을 빈 칸이나 쉼표(,) 포함해서 모두 몇 개의 문자들로 이뤄어져 있는지 세어보는 것이다. 모두 세어본 뒤 자신이 세어본 숫자와 일치한지 컨트롤 + F5를 통해 확인해보자.
#include <iostream>
#include <string>
int main() {
std::string str = "Hello, World!";
// 문자열의 길이를 반환
std::size_t length = str.length(); // 또는 str.size()를 사용할 수 있습니다.
// 길이를 출력
std::cout << "문자열의 길이: " << length << std::endl;
return 0;
}
모두 작성했다면 컨트롤 + F5로 문자열의 길이를 확인한뒤 아래 더보기를 눌러 정확하게 코드를 작성했을 시 출력되는 문자열의 길이를 알아보도록 하자.
만약 위와 똑같이 작성했다면 문자열의 길이는 '13'으로 나올 것이다.
자, 그럼 위의 코드를 설명해주도록 하겠다.
먼저 1번의 #include <iostream>은 앞서 말했듯이 입출력 스트림 라이브러리를 포함하는 것으로 이 라이브러리를 통해 표준 입력, 출력을 사용할 수 있다. 표준입력은 std::cout, 표준출력은 std::cin.
2번의 #include <string> 코드는 std::string 클래스를 사용하기 위해 필요한 문자열 라이브러리를 포함한 것으로 std::string은 C++에서 문자열을 다루기 위한 표준 클래스이다.
3번은 빈 줄로 빈 줄은 통상적으로 몇 개가 되든 상관 없다고 말했다.
4번의 int main() 은 저번에도 얘기 했듯이 대부분의 프로그래밍 언어들의 진입점(entry point)이자 시작점이다. 또 main 함수 이름 앞에 쓰여진 int는 이 함수는 정수형 값을 반환한다는 것을 의미하며 main은 함수의 이름이며 ()는 매개변수인데. 빈 공간으로 되어 있으니 매개변수를 받지 않음을 나타낸다. main 함수는 거의 항상 정수형(int)을 반환해야 하며 이는 프로그램이 종료될 때 운영체제에 반환하는 값을 의미한다. 보통 0으로 반환하면 프로그램이 성공적으로 종료되었음을 의미하며 0이 아닌 값은 프로그램의 오류나 비정상적인 프로그램 종료를 의미한다.
좀 더 자세히 main 함수의 역할을 설명하면 프로그램의 진입점이라고 설명하였는데, 모든 C++ 프로그램은 main 함수에서 시작된다, 프로그램이 실행되면 가장 먼저 main 함수가 호출되며 그 안에 작성된 코드들이 순차적으로 실행된다. 이후 프로그램 종료라는 건 결국 main 함수 종료를 의미하는데. 이때 return 문을 통해 프로그램의 종료 상태를 운영체제에 전달한다.
5번의 std::string str = "Hello, World";은 아래와 같이 설명하겠다.
str이라는 이름의 문자열 변수를 선언하고 "Hello, World!" 라는 값을 초기화(할당) 이후 std::string 클래스는 C++에서 문자열을 저장하고 조작하는데 사용된다.
6번은 빈 줄이고 7번은 8번에 쓰여진 코드를 설명하는 주석
8번 std::size_t length = str .length(); 코드 같은 경우 아래와 같이 설명하겠다.
먼저 str.length()는 문자열의 길이를 반환한다. 여기서 str은 5번에 작성된 변수 str을 의미한다. 그리고 문자열의 길이는 문자 수를 의미하는데 빈 공간, 특수문자를 모두 포함한다. 이후 이 값은 length라는 변수에 다시 저장된다. 여기서 주석에 설명이 되어 있듯이 str.length();는 str.size();로 사용해도 정상적으로 문자열의 길이가 반환된다.
9번은 다시 빈 줄이고 10번은 11번에 쓰여진 코드를 설명하는 주석
11번 std::cout << "문자열의 길이: " << length << std::endl; 은 아래와 같이 설명하겠다.
먼저 std::cout은 컨트롤 + F5로 실행시 콘솔창(명령프롬프트, CMD)에 문자열을 출력하는데 사용되며 이 줄에서 <<는 말햇듯이 연산자 중 하나로 이번엔 비트 시프트 연산자가 아닌 출력 연산자로 쓰인 것이고 하늘색 length 부분은 8번에 똑같이 하늘색인 length 변수의 값을 불러오는 것이며 std::endl은 줄 바꿈을 의미한다.
마지막으로 13번의 return 0; 이라는 코드는 4번에서 설명했듯이 main 함수는 정수를 반환하기 때문에 프로그램이 정상적으로 종료 되기 위해선 0이라는 값을 반환 받아야 한다.
그 밖에 std::string 클래스에서 제공하는 멤버 함수를 이용한 다른 기능들에 대해서도 간단하게 알아보자.
std::string str = "Hello, World!";
대략적인 코드들은 생략하고 위 코드를 기준으로 잡을때
std::string str = "Hello, World!";
str.clear();
위 코드에서 str.clear() 멤버 함수는 위에 써져 있는 문자열의 내용을 모두 지우고, 길이가 0인 빈 문자열로 만든다.
std::string str = "Hello";
str.append(", World");
std::cout << str << std::endl;
위 코드에서 append() 멤버 함수는 문자열의 끝에 다른 문자열을 추가한다.
std::string str = "Hello";
str += ", world!";
std::cout << str << std::endl;
위 코드에서 += 또한 append()와 동일한 기능을 하는데, += 연산자를 사용해 문자열을 결합할 수 있다.
그 밖에 다양한 기능들이 있으니 추가로 궁금하다면 구글링을 통해 알아보자.
마지막으로 hello World! 뒤에 적혀있는 \n은 개행 문자로 콘솔(명령프롬프트, CMD) 등에서 다음 줄 용도로 사용하는데. 예를들면
나는 블로그 <<라는 문장을 아래와 같이 출력하고 싶다면 이렇게 작성해야한다.
나는
블로그
위에처럼 출력하고 싶다면
나는\n블로그
위에처럼 작성하면 된다.
그럼 이번 글은 여기서 마치도록 하며 다음 글에선 cout가 아닌 cin과 변수, 상수(const)에 대해 알아보려고 한다.
'코딩과 프로그래밍 > C++' 카테고리의 다른 글
C++ 기초(1/10) (0) | 2024.08.20 |
---|