개요
마지막으로 썼던 글이 4월 29일입니다.
거의 한달만에 펜대를 잡는군요.
아아, 이 서늘하고도 묵직한 감각... 24일 만이구만.
놀랍게도 저는 저 글에서 이렇게 말한 바 있습니다.
분명히 설명했던 내용인 것 같은데 딴곳에다가 적었던 것 같군요.
나중에 헤더 관련으로 간단하게 글 한번 더 쓰겠습니다.진짜로! 1주 안에 헤더 글로 뵙죠.
안타깝게도 제가 생각하는 저보다 저는 그리 부지런한 인간이 아니였습니다.
물론 변명할 거리는 넘쳐납니다.
STA+C 준비도 해야했고... 수업도 너무 많았고... 수행평가도 이거저거 겹쳤고...
하지만 변명은 하남자만 하는법.
물론 저는 변명을 하겠습니다.
너무 STA+C이 바빴어요. 저번 주 금요일까지 정말 감기에 걸려 죽어가면서(진짜임) 까지 STA+C을 했습니다.
그리고 저번 주 금요일이 지난 후엔 열심히 쉬었습니다.
사실 다시 글을 쓰기 시작한건 5월 13일 경입니다.
새로 GPT-4o 라는 모델이 나왔지 뭡니까? 말도 안되는 이미지 분석력을 보이길래 한번 소재로 글을 써봐야 겠다 싶었죠.
근데 게임 관련된 글을 쓰고 싶었기 때문에 AI'만' 사용해서 게임 만들기 라는 키워드를 써봤습니다만...
딱히 GPT 3.5보다 특출나게 코드를 잘쓰는 편은 아니더군요.
그래서 약 3달러 가량의 제 피같은 돈을 날려먹고 글쓰기를 접었습니다.
AI 관련된 얘기 잠깐만 하자면 GPT-4 Turbo에 비해 출력물의 차이는 크게 없다고 느꼈습니다.
제가 문맹 수준의 독해력을 지녀서 그런 것일 수도 있지만 저는 그렇게 느꼈죠.
하지만 GPT-4o 는 토큰 당 가격 자체가 반값 싸졌습니다.
한글을 토큰으로 치환하는 효율성도 1.7배 올랐다고 합니다.
물론 가격은 부가적인거고 소리 생성도 할 수 있고 이미지 분석력도 올랐답니다.
이건 관심없고 그냥 속도가 매우 빠른게 맘에 듭니다.
...아무튼 슬슬 헤더에 관한 글로 들어가죠.
헤더란?
헤더(Header)라...
번역기는 머릿글, 정도로 번역해줍니다.
C++에서의 헤더는 외부 소스 파일에서 정의된 변수나 함수를 쓰기 위해 사용합니다.
'머릿글' 이라는 뜻과 일맥상통 하도록 보통 소스 파일의 가장 윗단에 작성합니다.
우리에게 많이 익숙한 헤더는 C언어를 한다면
#include<stdio.h>
<stdio.h>가 있을것이고
C++을 한다면
#include<iostream>
iostream이 있겠죠.
대체 이 헤더가 무엇을 하는 놈인지 오늘 한번 찾아보죠.
필수불가결한 존재
맞습니다. 헤더는 필수불가결한 존재입니다.
당장 C++ 소스 파일 하나 만들어서 헤더 없이 Hello World 출력을 시도 해보겠습니다.
int main()
{
cout << "Hello World!";
}
적자마자 저를 반겨주는 빨간줄에서 뜨는 오류는 다음과 같습니다.
음?
이건 헤더가 있어도 namespace 안쓴 휴먼 오류 아님?
좋습니다. 한번 std:: 를 붙여보죠.
int main()
{
std::cout << "Hello World!";
}
네... 그렇습니다.
우린 iostream이란 헤더 없이는 간단한 문자열 하나 출력하지 못합니다.
근데 확실히 하기 위해 GPT에게 헤더 없이 출력하는 법을 물어봤더니 이런 코드를 받았습니다.
extern "C" long syscall(long number, ...);
int main() {
const char* message = "Hello World\n";
long syscall_number_write = 1; // Syscall number for 'write' on x86_64
long file_descriptor_stdout = 1; // File descriptor for standard output
long message_length = 12; // Length of the message including the newline character
syscall(syscall_number_write, file_descriptor_stdout, message, message_length);
return 0;
}
실행이 안되길래 자세히보니 Linux 환경을 기준으로 작성되었다고 합니다.
아무튼 이 헤더란놈은 위에서 말했듯이 외부 소스 파일에서 정의된 변수나 함수를 쓰기 위해 사용합니다.
cout 이라는 객체또한 iostream이란 헤더 내에서 정의됐을 뿐 저희는 기본적으로 사용할 수 없습니다.
실제로 cout에 마우스 커서를 대고 F12를 눌러서 원본을 확인하러 가면 iostream 헤더로 이동하는 것을 확인할 수 있습니다.
어떻게 작동함?
이 헤더라는 것은 #include라는 키워드를 통해 받아옵니다.
이 헤더를 받아오는 키워드가 import가 아닌 include인 이유는 다 있습니다.
헤더를 받아오기 위해 #include 키워드를 사용하는 순간 include한 헤더의 전문이 소스파일에 그대로 복사 됩니다.
실제로 소스코드에 '포함(include)' 하는 것이죠.
만약 제가 Add.h 라는 헤더를 작성했다고 해봅시다.
//Add.h
int Add(int x, int y);
그렇다면 이것을 include한 소스파일은
#include "Math.h"
using namespace std;
int main()
{
cout << Add(1,5) << endl;
}
이렇게 보여도 사실
//Add.h
int Add(int x, int y);
using namespace std;
int main()
{
cout << Add(1,5) << endl;
}
이러한 꼴을 띄고 있습니다.
헤더와 소스파일의 분리
우리는 main 함수를 실행하는 소스 파일이 너무 복잡해지는 것을 막기 위해 여러가지의 기능을 헤더로 나누고 그 헤더를 헤더 파일과 구현하는 소스 파일로 다시 한번 나눕니다.
실제로 위의 예제를 봤을때 Add.h 안의 Add 라는 함수는 구현부가 존재하지 않습니다.
이러면 함수가 존재는 하니 당장 VS2022에서 오류를 뱉지는 않을지언정 당연하게도 실행 부분에서 오류가 납니다.
이때 우리는 이 헤더의 함수를 구현하는 소스 파일을 구분합니다.
Add.h 가 존재하니 Add.cpp 로 이름을 짓는것이 국룰입니다.
#pragma once
int Add(int x, int y);
다음과 같이 함수의 반환형, 이름, 매개변수를 정의만 해주고 구현은 소스 파일에 맡깁니다.
#include"Add.h"
int Add(int x, int y)
{
return x + y;
}
어떻게 보면 C#의 추상클래스와 상당히 비슷한 것 같아 보이기도 합니다.
헤더 가드
우리가 헤더 파일을 만들면 눈에 띄는 키워드가 하나 있습니다.
바로 #pragma once 인데요.
이것은 '헤더 가드' 라는 명칭으로 불립니다.
이게 무슨일을 해주냐?
저희가 똑같은 헤더를 두번 include 하는 경우를 방지해줍니다.
네? 저희가 아무리 능지가 떨어져도 똑같은 헤더를 두번 include 하는 경우는 없다구요?
아뇨, 육안으로만 그럴 뿐입니다.
Add.h 라는 헤더를 사용하는 Math.h 헤더가 있다고 해봅시다.
그리고 어떠한 소스 파일에 Add.h와 Math.h를 둘 다 include 했습니다.
이렇게 되면 Add 함수에 대한 정의가 완벽히 겹쳐버리기 때문에 오류가 발생하겠죠?
이 것을 방지하기 위해 있는 것이 헤더 가드 입니다.
헤더가 두개밖에 없으니 당장 크게 와닿지는 않지만 어떠한 프로그램 구현을 위해 여러가지 헤더를 만들다 보면 확실하게 감이 올겁니다.
물론 #pragma once는 헤더 파일을 생성할때부터 적혀있기 때문에 문제가 될일은 없습니다.
...이상한 문자열이라고 여기고 지워버리지만 않는다면 말이죠.
막간
막간을 이용해 짧게 헤더를 include 할때 <> 와 "" 의 차이를 알려드리겠습니다.
진짜 간단하게 C++ 표준 라이브러리는 꺽쇠(<>)를 사용하고 저희가 직접 만든 수제 헤더는 따옴표("") 를 사용합니다.
이유는 ""는 경로를 통해 가져오는 성질이 있는데 표준 라이브러리는 저희가 프로젝트를 만들었을때 경로에 있지 않고 어디 이상한 폴더에 동떨어져 있기 때문입니다.
...짧죠? 제가 짧다고 말씀 드렸잖아요.
마치는 말
한달 가까이 글을 안쓰다보니 글쓰는 실력이 죽었습니다.
코드 블록이 가독성을 해치는 것 같아서 마지막에 다와가는 중에 코드 블록 사용을 줄였는데 너무 줄인것 같기도 합니다.
아무튼 이제 진짜 바쁜 기간입니다.
STA+C에 야침차게 냈던 기획서가 개같이 망해버리면서 STA+C에선 벗어났지만 STA+C이 망했으니 다른 곳에 더욱 힘을 줘야겠죠.
금방 수업 정리 끝내고 게임엔진응용 개인 프로젝트 개발 일지로 찾아뵙겠습니다.
진짜로요. 이번엔 진짜임. 믿어주셈.
'개발 > C++' 카테고리의 다른 글
[C++] | extern "C"와 __declspec(dllexport)는 대체 뭔데 (0) | 2024.11.06 |
---|---|
게임 프로그래밍 | C++ | 빌드 (1) | 2024.04.29 |
자료구조 | C++ | 연산자 오버로딩 (Overload) (1) | 2024.04.23 |
C++ | 동적 배열 (3) | 2024.04.17 |
게임 프로그래밍 | C++ | 메모리 구조 (0) | 2024.04.17 |