static 멤버함수는 객체 없이 호출 가능
static 멤버함수 안에는 this가 없다. 그래서 일반적인 멤버변수를 사용할 수 없다.
zero division
int Value = 1 / 0; // zero division 에러
Value = 1 % 0; // zero division 에러
int zero = 0;
int a = 1 / zero; // zero division 에러
class Test {
public:
int Value;
void Function() {
this->Value = 20; // this가 null이기 때문에 null reference exception 발생
}
};
Test* CreateTest() {
return nullptr;
}
int main() {
Test* NewTest = CreateTest();
NewTest->Function();
return 0;
}
어디가서 질문할 때 "왜 터지는지 모르겠다"가 아니라 "왜 this가 null인지 모르겠다"라고 질문해야 한다.
char는 unsigned기준 0~255 범위 => 256개밖에 표현 못함.
한글 100% 표현 불가능
숫자 1개와 문자 1개를 매칭시키는 방법을 인코딩이라고 한다. 인코딩에는 방식이 많을 수밖에 없다. 문자를 표현하기 위한 바이트 크기들이 다르기 때문이다.
아스키 인코딩
문자를 7비트로 표현. 초기형 인코딩 방식.
아스키 인코딩 방식은 ansi 멀티바이트 방식이라고 불리는 방식에 통합된 방식이다. 한글을 고려할 필요가 없었다. 코딩에 필요한 문자가 256개에 매칭이 가능했다.
Ansi
아스키의 확장형 문자열 방식. 문자를 1바이트로.
MultiByte
어떤때는 1바이트 어떤 때는 2바이트로 표현하는 멀티바이트 방식이 만들어졌다. 65536개까지 가능해졌다. 한 나라의 문자는 모두 넣을 수 있어도 전세계의 문자를 넣을 수는 없었다. 국가코드라는 게 생겼다. 운영체제가 국가코드라는 것을 정함. 한국어 표현 가능해짐.
유니코드 == WideByte
그냥 다 2바이트로 하면 되는거 아니야? => 유니코드 혹은 와이드바이트 스트링이라고 불리는 방식이 만들어졌다.
문자를 2바이트로 표현. 전용 자료형인 wchar_t
를 c++에서 지원해준다.
표현식 : L""
UTF-8
문자를 1~4바이트로 표현. 전세계 모든 글자를 표현할 수 있다.
이모지부터 여러 문자의 형태까지.. 이게 UTF-8, UTF-16 시리즈들.
아무것도 안 붙이고 문자 사용하면 멀티바이트 방식으로 사용된다. L을 붙이고 사용하면 유니코드방식으로 사용하겠다는 의미가 된다. UTF-8은 u8문자열 방식으로 지원한다.
선생님은 멀티바이트를 기본으로 사용하고 필요시에 와이드 바이트나 UTF-8로 변환하여 사용할 예정. 그냥 char Arr[100] 쓴다는 뜻.
함수 사용하다보면 문자열 넣어야 할 때가 있다. 그런데 동작하지 않으면 내가 넣은 문자열의 값이 잘못된 것이 아니고 문자열 인코딩이 잘못되서 그럴 수 있다는 걸 생각할 수 있어야 한다.
string은 벡터라고 생각하면 편하다. reserve도 있고 capacity도 있고..
문자열 더하기 쉽다.
std::string Text0;
Text0.reserve(3);
Text0 = "가";
std::string Text1;
Text1.reserve(3);
Text1 = "나";
std::string Text2 = Text0 + Text1; // "가나"
동적할당을 많이 하다보면 램의 메모리에 데이터 사이 틈새 공간이 생긴다.
메모리를 할당한다 => 느려진다.
메모리를 할당하기 위해 빈 공간을 찾는다 => 느려진다.
메모리를 삭제한다 => 느려진다.
String을 쓸 때 함수에 값형으로 인자를 넘기는 코드는 이득이 거의 없기 때문에 주의해야 한다.
debug 모드는 최적화가 안 되어 있는 코드를 보여준다. 디버그 모드일 때는 인간이 이해하기 쉬운 모드로 변환하고 이름을 다 기억해 놓는다. 함수, 변수 이름 등을 다 기억해 놓는다.
release 모드에서는 최적화를 모두 끝낸 상태로 보이기 때문에 변수 A가 A의 이름으로 있지 않는다. 눈에 보이는 모습이 아닌 컴퓨터가 가장 빠르다고 생각하는 모습으로 변경시킨다.
release 모드에서도 중단점을 걸 수는 있지만 의미가 없다(값을 볼 수가 없음). 모든 최적화가 다 끝난 상태이기 때문에 3~5배 이상의 프레임이 오른다. 출시는 release로 해야 한다.
빌드하고 값을 확인했는데 말도 안되는 이상한 값이면 릴리즈모드인지 의심할 줄 알아야 함.
커밋하기 전에 디버그모드와 릴리즈모드 둘 다 컴파일 돌려보고 커밋하는 것이 좋다.
모든 구성으로 해놓고 속성 고쳤던 이유.
x86은 32비트를 말하고 과거에 쓰였던 빌드 방식.
x86에서는 포인터가 4바이트이다.
램이 4기가가 안되는 컴퓨터들이 많았다.
x64는 64비트임. 포인터 8바이트.
이제는 4기가 이하 램을 쓰는 컴퓨터를 찾는 게 어렵다.
Api(Application programming interface)
인터페이스 : 함수 클래스 멤버변수 멤버함수 등을 모조리 다 포함. 어떤 동작을 하는 코드를 사용하기 위한 모든 방법을 인터페이스라고 함.
ex) 소리를 재생하기 위한 함수가 있음 =>
"소리를 재생하기 위한 인터페이스를 제공했다, 소리를 재생하려면 xxx 클래스를 사용해야 한다.", "소리를 재생하려면 xxx클래스를 통한 인터페이스를 제공한다."
xxx 클래스에 xxxx 함수가 있다. xxx 클래스에는 xxxx 인터페이스가 존재한다.
WinApi
=> Window를 사용하기 위한 모든 클래스 방법 함수 변수 머시기 등등을 다 종합해서 Win 어플리케이션 프로그래밍 인터페이스라고 부른다.
윈도우에서 앱을 만들기 위한 기본적인 방법을 담아둔 옵션
프로젝트 만들자마자 실행
하위 시스템이 창으로 돼있음. 이거 때문에 진입점이 wWinMain으로 바뀌어있음.
이전에 CPP는 콘솔로 돼있었음.
hInstance
: 내 프로그램의 제어권한이자 표식 (xx번 프로그램)hwnd
: 윈도우 창을 제어할 수 있는 제어권한이자 표식 (xxx번 창)// WindowsProject1.cpp : 애플리케이션에 대한 진입점을 정의합니다.
//
#include "framework.h"
#include "WindowsProject1.h"
#define MAX_LOADSTRING 100
// 전역 변수:
HINSTANCE hInst; // 현재 인스턴스입니다.
WCHAR szTitle[MAX_LOADSTRING]; // 제목 표시줄 텍스트입니다.
WCHAR szWindowClass[MAX_LOADSTRING]; // 기본 창 클래스 이름입니다.
// 이 코드 모듈에 포함된 함수의 선언을 전달합니다:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
// 경고 레벨이 높아지면 인자를 사용하지 않아도 경고가 난다. 억지 사용하는 코드.
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// hInstance : program number
// TODO: 여기에 코드를 입력합니다.
// 전역 문자열을 초기화합니다.
//LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
//LoadStringW(hInstance, IDC_WINDOWSPROJECT1, szWindowClass, MAX_LOADSTRING);
swprintf_s(szTitle, L"title");
swprintf_s(szWindowClass, L"tttt");
// szWindowClass를 만드는곳?
MyRegisterClass(hInstance);
// 애플리케이션 초기화를 수행합니다:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINDOWSPROJECT1));
MSG msg;
// 기본 메시지 루프입니다:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// 함수: MyRegisterClass()
//
// 용도: 창 클래스를 등록합니다.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINDOWSPROJECT1));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WINDOWSPROJECT1); // nullptr넣으면 메뉴 안 뜸
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
// RegisterClassExW 윈도우에게 알려준다.
// WNDCLASSEXW wcex; 에 입력한 모양대로 띄워주라는 의미. 그리고 그 모양이 szWindowClass모양이라고 할게...
return RegisterClassExW(&wcex);
}
//
// 함수: InitInstance(HINSTANCE, int)
//
// 용도: 인스턴스 핸들을 저장하고 주 창을 만듭니다.
//
// 주석:
//
// 이 함수를 통해 인스턴스 핸들을 전역 변수에 저장하고
// 주 프로그램 창을 만든 다음 표시합니다.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
// hInst 내 프로그램의 제어권한이자 표식
hInst = hInstance; // 인스턴스 핸들을 전역 변수에 저장합니다.
// HWND hWnd 윈도우를 제어할 수 있는 제어권한이자 표식
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow); // hWnd 윈도우를 띄워주라는 뜻
UpdateWindow(hWnd);
//ShowCursor(false); no cursor
return TRUE;
}
//
// 함수: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// 용도: 주 창의 메시지를 처리합니다.
//
// WM_COMMAND - 애플리케이션 메뉴를 처리합니다.
// WM_PAINT - 주 창을 그립니다.
// WM_DESTROY - 종료 메시지를 게시하고 반환합니다.
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// 메뉴 선택을 구문 분석합니다:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: 여기에 hdc를 사용하는 그리기 코드를 추가합니다...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// 정보 대화 상자의 메시지 처리기입니다. help tab
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}