• 글로벌 변수선언


// 시간을 구하기 위한 변수들

LARGE_INTEGER g_tSecond;   // 초당 클록수    ex) 360  (고정값)

LARGE_INTEGER g_tTime;      // 이전 클록수    

float   g_fDeltaTime;   // (현재클록수 - 이전클록수) / 초당 클록수 --> ex 36 / 360



  • wWinMain() // 함수내에서...

{

QueryPerformanceFrequency(&g_tSecond);    // 초당 클록수 가져오기

QueryPerformanceCounter(&g_tTime);  // 이전 클록수 가져오기


}


  • void Run() // 함수내에서

{

// Run한번당 36클록만큼 진동한다.

// 1초당 360번 클록이진동한다.

// 그럼 10번 불리겠지 Run은? -> 10프레임(10틱)이라 가정하는것.

// 0.1 * 300 하면 30이겠지     -> Run한번당 1/10 * 300 = 30 이라는 계산이 진행된다.

// 30 * 10 = 300                  -> 근데 Run이 총 10번 불리니까 우리가 원하는 300이라는 속도가 1초에 만들어지는 것이다.


// DeltaTime을 구해준다.

LARGE_INTEGER tTime;

QueryPerformanceCounter(&tTime);    // 현재 클록수 가져오기


// 호출1번당 이동시간 = 현재와 이전 클록수의 차이  /  1초당 클록수  ex)   36/360  

g_fDeltaTime = (tTime.QuadPart - g_tTime.QuadPart) / (float)g_tSecond.QuadPart;


  // 그럼... 렉이 아주심하게 생겨서, 다음 Run()이 호출 되는데에 엄청난 딜레이가 생겼다 가정하자

  //  현재와 이전 클록수의 차이가 360보다 커지는 경우가 존재할수있을까?

  // 뭐 있다고 치자, 

  // 이때는 조건문등을 이용해 min값을 처리하는등의 문제로 처리할 수 있을 것 같다만

  // 이거에대한 고민은 조금더 나중에 해보자.


// 이전시간을 지금시간으로 초기화해준다.

g_tTime = tTime;


// 플레이어 초당 이동속도 : 300

float fSpeed = 300 * g_fDeltaTime;

}


타이머 참고사이트 http://www.tipssoft.com/bulletin/board.php?bo_table=FAQ&wr_id=735




1. __cdecl 


 C/C++에서 사용되는 기본적 사용 호출규약이다. 

 가변인수함수를 만들 수 있다는 장점을 가진다...

 호출을 하는자가 호출을 받는자의 스택프레임을 정리한다.


2. __stdcall


Win32 API에서 사용되며, 호출을 받는자가 스택을 정리한다. 

Win32 API에서는 가변 인수 함수가 없기 때문에, 매개변수의 개수가 고정적이다. 

이는 호출을 하는자에서 스택을 정리하는 것보다, 호출을 받는자가 스택을 정리하는게 더욱 효율적이다.


3. __fastcall 


스택이 아닌 가까운 레지스터를 사용함으로써 호출 속도가 빠르다.

호출을 받는자가 스택을 정리하나 스택을 사용하지 않고 레지스터를 이용하므로 

정리할 내용이 없어 따로 정리를 하지 않는다.




자세한 내용은 http://blog.eairship.kr/254 참고.

  • 싱글톤 사용의 목적 : 프로세스 내에 유일한 객체를 생성하여 사용하고 싶을 때

 - 1. 생성자를 private으로 감추어서 새로운 객체가 외부에서 마구 생성되는것을 방지한다.


 - 2. 유일하게 생성된 객체에 접근하는 방법을 제공한다. getInstance()등의 함수를 통한다 !


 + 전역변수와 비슷한 개념으로서 instance를 초기화해서 써준다.


출 처 : http://www.iamcorean.net/140






출처 : https://www.youtube.com/watch?v=s1nY96Efbjg



위의 코드에서 setValue()함수는 생략되었다고 생각하고 이해하자.


싱글톤에 대한 개념이 명확히 다가오지않을 때마다 참고하면 좋을 자료같아서 스크랩하였다.


C#에서는 static class개념을 이용하는게 좋다는 것도 잊지말기.

파일 입출력은 C언어 C++모두 함수가 존재하지만,


C언어를 쓰는게 조금더 대중적인 것 같다.


FILE * pfile = NULL;


이런식으로 파일스트림을 가리키는 포인터를 하나 만들어주고,


fopen_s(&pfile, "merong.txt", "rt");   


---> 파일을 열어주고 인자값으로 (&파일스트림, 텍스트파일 이름, 파일모드)


파일모드에서 앞에 붙는 r, w 의 뜻은

read / write 이며,

뒤에 붙는 t, b의 뜻은

text / binary 의 뜻이다.


text는 사람이 읽기 좋은형태,

binary는 컴퓨터가 읽기좋은 형태라 보면

이해하기 쉽다.


if(pfile)        

// 정상적으로 열리지않는다면 위에 fopen_s에서 pfile에 NULL인 0의 값이

// 리턴되었을것이기에 정상적으로 열렸을때만 if문에 들어오게된다.

{

char str[100]="abcdefg";
fwrite(str, sizeof(데이터형), 개수 , pfile); 


fclose(pfile);


}


str은 내가 가져올 것이 문자일경우를 예로 char형으로 만든 배열이고,

fwrite는 파일에 내용을 쓸때 쓰는 함수로, 인자값으로는 

( 파일에 쓸 내용을 가져올 공간의 주소 , 해당자료형의 사이즈 , 개수 , 파일스트림)

의 형태로 쓴다.


위와 비슷한 형태로

fread를 쓸 수 있는데, 파일에서 내용을 읽어올때 쓴다.

인자 값의 형태는,

( 파일의 내용을 읽어올 공간의 주소,  해당자료형의 사이즈, 개수, 파일스트림이다.)

요즘 코딩 하기를 너무 미루게된다...

별거아닌것부터 하기 싫어하는게 7월 초랑 너무 계획이 틀어지고 있는 것 같기도...



더블링크드리스트를 만들어보면서 느꼈던점...


왜 대부분 더블링크드리스트의 정렬을 할때,

선을 이어주는걸 바꿔주는지를 잘 모르겠다.


두 노드를 바꾸려고 할때,

두 노드의 앞 뒤 노드를 저장하여,

서로 선을 바꿔주는 식인데,


이렇게 하면 두 노드의 스왑이 너무 복잡해진다.


바로 붙어있는경우는 6개의 줄을 새로이 이어주어야하고,

떨어져있는 경우는 8개의줄을 이어주어야하기 때문이다.. ㄷㄷ;;


따라서, 노드안에있는 데이터만을

바꿔주는게 더욱 이해하기 쉬운 코드이며,

효율적인것에서도 더욱 뛰어날거로 예상된다.

(물론 데이터가 어마무시하게 크면 안되겠지만..)


잘 모르겠으면 그림판부터 켜서 그려보자 !

 


아직 제네릭링크드리스트까진 하진않았지만,

그전에 몇 번더 구현해보는게 좋을 것 같다.

생각보다 게을러서 금방 할 수 있는일을 미루다보면,

지식이 얕게 쌓이게되는것 같다.


반성하고 반성해야할 7월말이다.


  • C++의 동적할당

C나 C++ 모두 heap 메모리에 동적할당을 해줄 수 있는데,


이는 사용히 조심해야한다. 왜냐하면 프로그램 종료시 알아서 해제가 안되기 때문이다.


C++에서는 new키워드를, C에서는 흔히 malloc() 함수를 쓴다. 

( calloc()과 realloc() 함수의 차이는 다음에)




#include <iostream>
#pragma warning (disable : 4996)

int main()
{
	int * pNumber = new int;
	int * pNumber2 = new int[50];
	int(*pNumber3)[50] = new int[100][50];


	delete pNumber;
	delete[] pNumber2;
	delete[] pNumber3;

	return 0;
}



위 에서 보면 delete 키워드를 써서 new로 할당한 공간을 없애준다 볼 수 있는데,


주의 할점은 배열인경우 차원에 상관없이


 delete[] 변수명; 의 1개의 형태로만 delete를 한다는 것이다. 

#include <stdio.h>
#pragma warning (disable : 4996)

int main()
{
	char str[100];
	double pi = 3.141592;
	sprintf(str, "원주율 값은 %.2lf 입니다. ", pi);
	printf("%s \n", str);
	return 0;
}


여기서 sprintf의 함수의 효과를 알 수 있는데, 


출력하는 것이아닌 문자열을 담는 str변수에 %.2lf 에대한 값인 pi를 넣어준뒤


 str변수에 넣어준다고 생각하면 된다.

'ComputerScience > 꿀같은 예제들' 카테고리의 다른 글

C++ 다이아몬드 별찍기  (0) 2018.07.04
C++ 야구게임 만들기 (셔플함수이용)  (0) 2018.07.04
10진수 16진수 변환하기  (0) 2018.07.03
namespace  (0) 2018.07.02
  • 시간간격 이용법

여태까지 예제를 만들었던것은  프레임당 시간을 고려하지 않고 제작했었는데,


게임 프로그램의 기본구조를 이해하고 나니 잘못하고 있다는 것을 알았다.


그렇기때문에 2일전에 만들었던 범버맨에 기본구조의 형태를 


도입함으로 조금더 게임다운 구조를 만들었다.




이런형식으로 while문 안에 while문을 하나 더 넣어


시간이 어느정도 차이 이상일때만... 나오게하여 너무 빨리 화면이 렌더링 되는 것을


막을 수 있다. ( 33이라는 숫자는 1000/30 = 33.33333 에서 나온 수치이다.  --> 30프레임 기준)



  • _kbhit() 함수

그리고 여태내가 놓쳤던 부분이 있는데, 키보드입력시


_kbhit()함수를 써서 if문을 통해 처리를 해야


키보드 입력받기전에도 자연스럽게 게임이 렌더링되며


반복문을 반복할 수 있다.



페이지 플리핑, 프레임워크, 함수호출규약(http://blog.eairship.kr/254 참고) 에 대한 정리는

 나중에 직접사용하고 다시 하기로 하고...



  • sprintf() 함수

printf() 함수는 모니터에 출력하는 반면 sprintf() 함수는 문자열에 출력하는 함수이다.







  • 컴파일러가 자동으로 추가해주는 것들
  1.  default 생성자
  2.  default 소멸자
  3.  default 대입연산자
  4.  default 복사생성자 (얕은복사)


블로그 작성을 약 1주일만에 하는 것 같다.
여러 일들이 있었지만 공부를 손에 놓지 않는 것이 중요하다 생각하기에,
조금더 열심히 달려보아야지..

  • 실행파일과 메모리 영역 -> Memory (RAM)안에서도 이렇게 나뉠 수 있다.
1. Text 영역 (2영역으로 나뉘는데) -> 실행코드가 잡히는 영역( exe file )
 - 실행 code :  기계어 코드(4의 배수번지 지킨다)
 - string 영역 : 가변길이상수라서? 4의 배수 번지를 못지킨다.?


* Read Only 영역이라 MMU가 보고있다가 os에게 write시 알려준다보면 된다. ( 실행도중 바뀌면 큰일나는 영역이다)


2. Data 영역

 - data : extern변수와 static 변수 초기화된 애가 잡히는 곳 ( ex. int b =8 )

 - bss : 초기화되지 않은 아이들이 잡히는 곳. extern 같은경우는 초기화하지 않아도 저절로 0으로 초기화되어 여기로 잡힌다. ( ex. int=8 )


3. Heap 영역

 - 동적 memory 할당 시 필요한 저장공간 stack과 유동적인 크기라고 보면된다. (OS에 따라서)


4. Stack 영역

 - auto 변수가 잡히는 공간


+ 5. ) CPU내의 Register 공간

 - 레지스터변수가 할당되는 공간이다. 자동초기화는 되지않고, 일반적인 변수보다 빠른대신 영역이 더욱 한정적이다 볼 수 있다.



---> 처음 RAM은 모두 0인 상태나 다름없다, 다만 우리가 보는 쓰레기값은 예전에 어디선가 썼던 의미가 있던 값이다.

---> 따라서 중요한 정보들은 free전에 0으로 만들어서 free를 해주는 습관을 가져야 한다.




  • 참조와 포인터의 차이
int a ;
int &b = a ;  // 여기서 '='는 이름을 엮어주는 기호이지, bit copy의 개념으로 보면 이해하기 힘들어진다.

만약 a의 주소가 100번지라고 가정하자,
이때 int &b =a ; 를 한다고 하면, (b의 주소는 200번지라고 가정)
b는 특수포인터로서 const느낌을 가진다고 보면 이해하기 좋다.
다시말해, a가아닌 다른 memory를 가리키지 못하게 된다. 


여기서 cout << &b ; 를 하게 된다고 하면, 

b의 주소가 구해질거라 생각하지만,

a라는 변수의 변명일뿐인 b는 주소를 우리가 알 수가 없다. (왜요? 그렇게 만들었으니까..)

따라서 내부적으로 &*b로의 변환을거쳐 결국 b가 가리키는

a의 주소인 100번지가 찍혀지게 된다.


그럼 참조변수는 왜쓰는 것이고, 물리적으로는 어떻게 처리가 될까?

일단 참조변수는 pointer기호 없이 여러연산등을하고 표현 할 수 있기 때문에 쓰기 편하다는 장점이 있다.

참조변수는 별도의 메모리가 잡히고, 1번에 4Byte씩 잡힌다고 보면 된다.



  • 멤버참조연산자(.)와 간접멤버참조(->)연산자


struct Person x ;

struct Person *p = &x ;


위의 Person구조체에서 age라는 멤버가 있을때, 접근하기위한 대표적인 방법은 두가지 방법이 있다.


x.age = 20 ; 와 같이 구조체변수명 . member명으로 접근할 수 있다. 

p->age= 20 ; 는 (*p).age와 같이 (* + .) 의 개념으로 ->가 해석 될 수 있다. ( . 은 참고로 연산자 우선순위에서 1순위 )

따라서 (&x)->age = 20 ; 과 같은 모습이라 생각하면 이해하기 쉬울 것 이다.  

+ Recent posts