[TIL] 24-01-05

Lev·2024년 1월 5일
0

📓TIL Archive

목록 보기
18/33

전처리문

#define

/*
[전처리문]
#include "파일명"	=> 파일 치환
// 주석				=> 주석
#define 코드		=> 코드 치환 (new!)
*/

// define 코드 치환
#define TEN 10
#define TENTEN 10;	// ; 를 치환...?!
#define MYTEXT = "AAAAAAA"	// = 를 치환...?!
#define MYTEXT2 MYTEXT	// 이중 치환...?!

// define 매크로 함수
#define PLUS(Value) Value + Value
#define MUL(Value) Value * Value

// 요즘엔 잘 사용하지 않는다
// inline이 있기도 하고, 헷갈리기 때문이다

int main()
{
	int Value0 = TEN;	// int Value0 = 10;
	int Value1 = TENTEN	// int Value1 = 10;
	char Arr0[100] MYTEXT;	// char Arr0[100] = "AAAAAAA"
	char Arr1[100] MYTEXT2;	// char Arr1[100] = "AAAAAAA"

	int Value2 = PLUS(20);	// int Value2 = 20 + 20;
	int Value3 = MUL(PLUS(20));	// int Value3 = 20 + 20 * 20 + 20
	// 말그대로의 치환이라 알아서 괄호가 쳐진다거나 하지 않는다
}

디버깅

assert

#include <Windows.h>	// 윈도우 헤더
// 플랫폼 헤더 => 다른 OS에서는 사용할 수 없다
// C++은 해줄 수 없고, 윈도우만이 해줄 수 있는 것
#include <assert.h>

int main()
{
	MessageBoxA(nullptr, "X의 크기가 0입니다", "치명적 에러", MB_OK);
	// 메세지 창을 띄워주는 함수
	// 사용자가 OK를 누를 때까지 프로그램을 멈춰준다.

	assert(false);
	// 프로그램을 파괴할 수 있는 함수
	// 해서는 안될 사용을 저질렀을 경우, 일부러 심각한 익셉션을 일으켜 프로그램을 중지시킨다.
}

호출스택

/*
[호출스택]
F5 -> 중단점에 걸림 or 치명적인 오류 발생
이 때에는 반드시 호출스택 창을 확인하자!

- 보는 법
가장 상단이 가장 마지막에 실행된 함수
아래로 갈수록 이전에 실행된 함수
그 시점의 스택 메모리 상황이 기록되어 있다
호출 스택에서 에러/중단점으로 멈춰 있는 부분 이전에 실행된 함수의 상태를 확인할 수 있다

- 여는 법
상단 메뉴 -> 디버그 -> 창 -> 호출 스택
(F5를 누르지 않았을 때에는 열 수 없고, 반드시 디버깅이 시작되어야만 열 수 있다)
*/

Console Game (ConsoleScreen() 구현)

// [ConsoleEngine/EngineDebug.h]
#pragma once

#define MsgBoxAssert(TEXT) MessageBoxA(nullptr, TEXT, "치명적 에러", MB_OK); assert(false);
// MessageBoxA(nullptr, "콘솔스크린을 생성할 수 없습니다", "치명적 에러", MB_OK);
// assert(false);
// 본래 이렇게 두 줄을 입력해주어야 하지만, #define 전처리문을 사용하여 간략화했다
// [Galaga/Galaga.cpp]
#include <ConsoleEngine/ConsoleScreen.h>

int main()
{
	ConsoleScreen NewScreen = ConsoleScreen();

	NewScreen.CreateScreen(2, 2);
}

1차원 배열로 구현할 경우

// [ConsoleEngine/ConsoleScreen.h]
#pragma once
#include "EngineDebug.h"
// 디버깅은 최고 상위개념이나 마찬가지라 헤더파일의 헤더에 포함시켜도 된다

/*
정적 할당 => 프로그램이 실행되면 변경이 불가능하다
동적 할당 => 메모리 생성 지연을 지연시킬 수 있다

둘 중에 어떤게 더 좋다 나쁘다가 아니고, 각자의 역할이 있다.
*/

class ConsoleScreen
{
public:
	void CreateScreen(int _ScreenX, int _ScreenY);

private:
	int Value;	// 클래스 생성 => 동시에 즉시 생성
	int* Ptr;	// new int(); => 언제 생성될지 프로그래머가 정할 수 있음

	int ScreenX = -1;
	int ScreenY = -1;
	// -1로 초기화를 해두는 이유는, 초기화가 되지 않았다는 것을 표현하기 위함이다

	char* ScreenData = nullptr;
	/*
	char Arr[10][10]; => 사실 char Arr[10 * 10]; 이나 마찬가지

	2차원 배열이란, 인간의 편의성을 위해 만든 것이다.
	램이 구조상 1차원이기 때문에 실제로 2차원인 것은 아니다.
	*/
};
// [ConsoleEngine/ConsoleScreen.cpp]
#include "ConsoleScreen.h"
#include <iostream>
#include <Windows.h>
#include <assert.h>

void ConsoleScreen::CreateScreen(/*&NewScreen => this, */int _ScreenX, int _ScreenY)
{
	if (_ScreenX <= 0)
	{
		MsgBoxAssert("스크린 X 크기가 0이기 때문에 콘솔스크린을 생성할 수 없습니다.");
	}

	if (_ScreenY <= 0)
	{
		MsgBoxAssert("스크린 Y 크기가 0이기 때문에 콘솔스크린을 생성할 수 없습니다.");
	}

	/*this->*/ScreenX = _ScreenX;
	/*this->*/ScreenY = _ScreenY;

	// (1) 스크린에 총 몇 칸이 필요한지 계산
	int ArrayCount = (ScreenX + 1) * ScreenY + 1;
	// 2차원 배열이지만, 결국 1차원 배열이나 마찬가지이기 때문이다
	// ScreenX + 1 을 하는 이유는, 마지막에 줄바꿈기호를 넣기 위해서이다

	// (2) 동적 할당으로 새로운 스크린 생성하고 모든 칸을 0으로 초기화
	ScreenData = new char[ArrayCount] {0, };

	for (int y = 0; y < ScreenY; y++)
	{
		// (3) 각 줄 (ScreenX - 1)번째 칸까지 *로 채우기
		for (int x = 0; x < ScreenX; x++)
		{
			int Index = y * (ScreenX + 1) + x;
			ScreenData[Index] = '*';
		}

		// (4) 각 줄 ScreenX번째 칸 \n으로 채우기
		int ReturnIndex = y * (ScreenX + 1) + ScreenX;
		ScreenData[ReturnIndex] = '\n';
	}

	// (5) 가장 마지막칸 0으로 채우기 ((2) 단계가 있기 때문에 선택적)
	ScreenData[ArrayCount - 1] = 0;

	printf_s(ScreenData);

	/*
	문자열이 출력되는 방법

	"**************\n
	 **************\n
	 **************\n
	 **************\n
	 **************\n
	 **************\n
	 **************\n"0

	
	e.g. ScreenX = 2, ScreenY = 2인 경우

	실제 모습						출력되는 모습
	[*][*][\n][*][*][\n][0]			**
									**
	*/
}

2차원 배열로 구현할 경우

// [ConsoleEngine/ConsoleScreen.h]
#pragma once
#include "EngineDebug.h"

class ConsoleScreen
{
public:
	void CreateScreen(int _ScreenX, int _ScreenY);

private:
	int ScreenX = -1;
	int ScreenY = -1;

	char** ScreenData = nullptr;	// 이중포인터로 변경
};
// [ConsoleEngine/ConsoleScreen.cpp]
#include "ConsoleScreen.h"
#include <iostream>
#include <Windows.h>
#include <assert.h>

void ConsoleScreen::CreateScreen(/*&NewScreen => this, */int _ScreenX, int _ScreenY)
{
	// 함수가 실행되었다는 것을 스택영역에 그릴 때,
	// 맴버함수의 경우 실행되면 내부에 this가 존재한다는 것을 기억해야 한다

	if (_ScreenX <= 0)
	{
		MsgBoxAssert("스크린 X 크기가 0이기 때문에 콘솔스크린을 생성할 수 없습니다.");
	}

	if (_ScreenY <= 0)
	{
		MsgBoxAssert("스크린 Y 크기가 0이기 때문에 콘솔스크린을 생성할 수 없습니다.");
	}

	/*this->*/ScreenX = _ScreenX;
	/*this->*/ScreenY = _ScreenY;

	// (1) 동적 할당으로 스크린 세로 줄 생성
	ScreenData = new char* [ScreenY];

	for (int y = 0; y < ScreenY; y++)
	{
		// (2) 동적 할당으로 각 줄별 스크린 가로 생성하고 모든 칸 0으로 초기화
		ScreenData[y] = new char[ScreenX + 2] {0, };

		// (3) 각 줄 (ScreenX - 1)번째 칸까지 *로 채우기
		for (int x = 0; x < ScreenX; x++)
		{
			ScreenData[y][x] = '*';
		}

		// (4) 각 줄 ScreenX번째 칸 \n으로 채우기
		ScreenData[y][ScreenX] = '\n';
	}

	for (int y = 0; y < ScreenY; y++)
	{
		printf_s(ScreenData[y]);
	}

	/*
	문자열이 출력되는 방법

	"**************\n"0
	"**************\n"0
	"**************\n"0
	"**************\n"0
	"**************\n"0
	"**************\n"0
	"**************\n"0


	e.g. ScreenX = 2, ScreenY = 2인 경우

	실제 모습						출력되는 모습
	[*][*][\n][0]					**
	[*][*][\n][0]					**
	*/
}

profile
⋆꙳⊹⋰ 𓇼⋆ 𝑻𝑰𝑳 𝑨𝑹𝑪𝑯𝑰𝑽𝑬 ⸝·⸝⋆꙳⊹⋰

0개의 댓글